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