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}