valhalla_client/
elevation.rs

1pub use crate::shapes::ShapePoint;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5#[serde_with::skip_serializing_none]
6#[derive(Serialize, Default, Debug, PartialEq, Clone)]
7/// Request to the elevation service.
8pub struct Manifest {
9    id: Option<String>,
10    height_precision: Option<HeightPrecision>,
11    range: Option<bool>,
12    resample_distance: Option<f64>,
13    shape: Option<Vec<ShapePoint>>,
14    encoded_polyline: Option<String>,
15    shape_format: Option<ShapeFormat>,
16}
17impl Manifest {
18    /// Creates a new [`Manifest`] builder.
19    pub fn builder() -> Self {
20        Default::default()
21    }
22    /// Name your route request.
23    ///
24    /// If id is specified, the naming will be sent through to the response.
25    pub fn id(mut self, id: impl ToString) -> Self {
26        self.id = Some(id.to_string());
27        self
28    }
29    /// Controls whether the returned array is one-dimensional (height only, the default) or two-dimensional (range and height).
30    ///
31    /// This can be used to generate a graph along a route, because a 2D-array has values for x (the range) and y (the height) at each shape point.
32    /// Steepness or gradient can also be computed from a profile request (e.g. when range = `true`).
33    ///
34    /// Default: `false`
35    pub fn include_range(mut self) -> Self {
36        self.range = Some(true);
37        self
38    }
39    /// Specifying the distance (in meters) at which the input polyline is sampled in order to provide uniform distances between samples along the polyline.
40    pub fn resample_distance(mut self, resample_distance_meters: f64) -> Self {
41        self.resample_distance = Some(resample_distance_meters);
42        self
43    }
44    /// Allows increasing the returned precision for heights.
45    ///
46    /// The default of returning as integer values works fine for most cases.
47    /// However, when charting elevation results along a nearly flat road can lead to "stair step" changes in elevation.
48    ///
49    /// Default: [`HeightPrecision::ZeroDecimalPlaces`]
50    pub fn height_precision(mut self, height_precision: HeightPrecision) -> Self {
51        self.height_precision = Some(height_precision);
52        self
53    }
54    /// Specifies whether the polyline is encoded with
55    /// - 6 digit precision ([`ShapeFormat::Polyline6`]) or
56    /// - 5 digit precision ([`ShapeFormat::Polyline5`]).
57    ///
58    /// Default: [`ShapeFormat::Polyline6`], meaning the encoded polyline is expected to be 6 digit precision.
59    pub fn shape_format(mut self, shape_format: ShapeFormat) -> Self {
60        debug_assert!(self.shape.is_none(), "shape is set and setting the shape_format is requested. This combination does not make sense: shapes and encoded_polylines as input are mutually exclusive.");
61        self.shape_format = Some(shape_format);
62        self
63    }
64    /// Latitudes/longitudes where the elevation data is desired in decimal degrees.
65    ///
66    /// The input coordinates can come from many input sources, such as a GPS location, a point or a click on a map, a geocoding service, and so on.
67    /// The locations are visited in the order specified.
68    pub fn shape(mut self, shape: impl IntoIterator<Item = impl Into<ShapePoint>>) -> Self {
69        debug_assert!(self.shape_format.is_none(), "shape_format is set and setting a shape is requested. This combination does not make sense: shapes and encoded_polylines as input are mutually exclusive.");
70        debug_assert!(self.encoded_polyline.is_none(), "encoded_polyline is set and setting a shape is requested. This combination does not make sense: shapes and encoded_polylines as input are mutually exclusive.");
71        self.shape = Some(shape.into_iter().map(|s| s.into()).collect());
72        self
73    }
74    /// A set of polyline encoded latitude/longitude pairs of a line or shape where the elevation data is desired.
75    ///
76    /// Details on polyline encoding and decoding can be found [here](https://valhalla.github.io/valhalla/decoding/).
77    /// See [`Self::shape_format`] to set the precision of the polyline.
78    pub fn encoded_polyline(mut self, encoded_polyline: impl ToString) -> Self {
79        debug_assert!(self.shape.is_none(), "shape is set and setting the encoded_polyline is requested. This combination does not make sense: shapes and encoded_polylines as input are mutually exclusive.");
80        self.encoded_polyline = Some(encoded_polyline.to_string());
81        self
82    }
83}
84
85/// Specifies the precision (number of decimal places) of all returned height values.
86#[derive(serde_repr::Serialize_repr, Debug, Clone, Copy, PartialEq, Eq, Default)]
87#[repr(u8)]
88pub enum HeightPrecision {
89    /// Zero decimal places (="integer precision") of precision for all height values
90    ///
91    /// Example: `123`
92    #[default]
93    ZeroDecimalPlaces = 0,
94    /// One decimal places of precision for all height values
95    ///
96    /// Example: `123.3`
97    OneDecimalPlace,
98    /// Two decimal places of precision for all height values
99    ///
100    /// Example: `123.34`
101    TwoDecimalPlaces,
102}
103
104#[derive(Serialize, Debug, Clone, Copy, PartialEq, Eq, Default)]
105/// Specifies the precision (number of decimal places) of the encoded polyline.
106pub enum ShapeFormat {
107    /// polyline is encoded with 6 digit precision
108    #[serde(rename = "polyline6")]
109    #[default]
110    Polyline6,
111    /// polyline is encoded with 5 digit precision
112    #[serde(rename = "polyline5")]
113    Polyline5,
114}
115
116#[derive(Deserialize, Debug, Clone)]
117/// Response to the request.
118pub struct Response {
119    /// Name of the route request.
120    ///
121    /// If id is specified via [`Manifest::id`] the naming will be sent through to the response.
122    pub id: Option<String>,
123    /// The specified shape coordinates from the input request.
124    ///
125    /// `None` if requested enabled via [`Manifest::shape`]
126    pub shape: Option<Vec<ShapePoint>>,
127    /// The specified encoded polyline, with six degrees of precision, coordinates from the input request.
128    ///
129    /// `None` if requested enabled via [`Manifest::encoded_polyline`]
130    pub encoded_polyline: Option<String>,
131    /// The 2D array of range (x) and height (y) per input latitude, longitude coordinate.
132    ///
133    /// `None` if not enabled via [`Manifest::include_range`]
134    pub range_height: Vec<Option<(f64, Option<f64>)>>,
135    /// The range or distance along the input locations.
136    ///
137    /// It is the cumulative distance along the previous latitiude, longitude coordinates up to the current coordinate.
138    /// The x-value for the first coordinate in the shape will always be 0.
139    pub x_coordinate: Option<f64>,
140    /// The height or elevation of the associated latitude, longitude pair.
141    ///
142    /// The height is returned as null if no height data exists for a given location.
143    pub y_coordinate: Option<f64>,
144    /// An array of height for the associated latitude, longitude coordinates.
145    #[serde(default = "Vec::new")]
146    pub height: Vec<f32>,
147    /// This array may contain warning objects informing about deprecated
148    /// - request parameters,
149    /// - clamped values
150    /// - etc.
151    #[serde(default = "Vec::new")]
152    pub warnings: Vec<Value>,
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    #[test]
159    fn serialisation() {
160        let manifest = Manifest::builder();
161        assert_eq!(
162            serde_json::to_value(&manifest).unwrap(),
163            serde_json::json!({})
164        );
165    }
166
167    #[test]
168    fn test_serialize_encoded_polyline() {
169        let manifest = Manifest::builder()
170            .id("some_id")
171            .height_precision(HeightPrecision::OneDecimalPlace)
172            .include_range()
173            .encoded_polyline("polyline")
174            .shape_format(ShapeFormat::Polyline6);
175        assert_eq!(
176            serde_json::to_value(&manifest).unwrap(),
177            serde_json::json!({"id":"some_id","height_precision":1,"range":true,"encoded_polyline":"polyline","shape_format":"polyline6"})
178        );
179    }
180}