valhalla_client/costing/motorcycle.rs
1//! Costing options for motorcycle routing
2use serde::Serialize;
3
4#[serde_with::skip_serializing_none]
5#[derive(Serialize, Debug, Clone, Default, PartialEq)]
6struct MotorcycleCostingOptionsInner {
7 maneuver_penalty: Option<f32>,
8 gate_cost: Option<f32>,
9 gate_penalty: Option<f32>,
10 private_access_penalty: Option<f32>,
11 destination_only_penalty: Option<f32>,
12 toll_booth_cost: Option<f32>,
13 toll_booth_penalty: Option<f32>,
14 ferry_cost: Option<f32>,
15 use_ferry: Option<f32>,
16 use_highways: Option<f32>,
17 use_tolls: Option<f32>,
18 use_living_streets: Option<f32>,
19 use_tracks: Option<f32>,
20 service_penalty: Option<f32>,
21 service_factor: Option<f32>,
22 country_crossing_cost: Option<f32>,
23 country_crossing_penalty: Option<f32>,
24 shortest: Option<bool>,
25 use_distance: Option<f32>,
26 disable_hierarchy_pruning: Option<bool>,
27 top_speed: Option<f32>,
28 fixed_speed: Option<u32>,
29 closure_factor: Option<f32>,
30 ignore_closures: Option<bool>,
31 ignore_restrictions: Option<bool>,
32 ignore_oneways: Option<bool>,
33 ignore_non_vehicular_restrictions: Option<bool>,
34 ignore_access: Option<bool>,
35 // -- ↓ auto / motorcycle only ↓ --
36 speed_types: Option<UsedSpeedSources>,
37 height: Option<f32>,
38 width: Option<f32>,
39 exclude_unpaved: Option<bool>,
40 exclude_cash_only_tolls: Option<bool>,
41 include_hov2: Option<bool>,
42 include_hov3: Option<bool>,
43 include_hot: Option<bool>,
44 // -- ↓ motorcycle only ↓ --
45 use_trails: Option<f32>,
46}
47
48/// By default, motorcycle costing will default to higher class roads.
49/// The costing model recognizes factors unique to motorcycle travel and offers options for tuning
50/// motorcycle routes.
51#[derive(Serialize, Debug, Clone, Default, PartialEq)]
52pub struct MotorcycleCostingOptions {
53 motorcycle: MotorcycleCostingOptionsInner,
54}
55impl MotorcycleCostingOptions {
56 #[must_use]
57 /// Creates a new instance of [`MotorcycleCostingOptions`].
58 pub fn builder() -> Self {
59 Self::default()
60 }
61
62 /// A cost applied when a [gate](http://wiki.openstreetmap.org/wiki/Tag:barrier%3Dgate) with
63 /// undefined or private access is encountered.
64 ///
65 /// This cost is added to the estimated time / elapsed time.
66 ///
67 /// Default: `30` seconds
68 pub fn gate_cost(mut self, gate_cost: f32) -> Self {
69 self.motorcycle.gate_cost = Some(gate_cost);
70 self
71 }
72 /// A penalty applied when a [gate](https://wiki.openstreetmap.org/wiki/Tag:barrier%3Dgate) with
73 /// no access information is on the road.
74 ///
75 /// Default: `300` seconds
76 pub fn gate_penalty(mut self, gate_penalty: f32) -> Self {
77 self.motorcycle.gate_penalty = Some(gate_penalty);
78 self
79 }
80 /// A penalty applied when a [gate](https://wiki.openstreetmap.org/wiki/Tag:barrier%3Dgate) or
81 /// [bollard](https://wiki.openstreetmap.org/wiki/Tag:barrier%3Dbollard) with `access=private`
82 /// is encountered.
83 ///
84 /// Default: `450` seconds
85 pub fn private_access_penalty(mut self, private_access_penalty: f32) -> Self {
86 self.motorcycle.private_access_penalty = Some(private_access_penalty);
87 self
88 }
89 /// A penalty applied when entering a road which is only allowed to enter if necessary to reach
90 /// the [destination](https://wiki.openstreetmap.org/wiki/Tag:vehicle%3Ddestination).
91 pub fn destination_only_penalty(mut self, destination_only_penalty: f32) -> Self {
92 self.motorcycle.destination_only_penalty = Some(destination_only_penalty);
93 self
94 }
95 /// A cost applied when a [toll booth](http://wiki.openstreetmap.org/wiki/Tag:barrier%3Dtoll_booth)
96 /// is encountered.
97 ///
98 /// This cost is added to the estimated and elapsed times.
99 ///
100 /// Default: `15` seconds
101 pub fn toll_booth_cost(mut self, toll_booth_cost: f32) -> Self {
102 self.motorcycle.toll_booth_cost = Some(toll_booth_cost);
103 self
104 }
105 /// A penalty applied to the cost when a
106 /// [toll booth](http://wiki.openstreetmap.org/wiki/Tag:barrier%3Dtoll_booth) is encountered.
107 ///
108 /// This penalty can be used to create paths that avoid toll roads.
109 ///
110 /// Default: `0`
111 pub fn toll_booth_penalty(mut self, toll_booth_penalty: f32) -> Self {
112 self.motorcycle.toll_booth_penalty = Some(toll_booth_penalty);
113 self
114 }
115 /// A cost applied when entering a ferry.
116 ///
117 /// This cost is added to the estimated and elapsed times.
118 ///
119 /// Default: `300` seconds (5 minutes)
120 pub fn ferry_cost(mut self, ferry_cost: f32) -> Self {
121 self.motorcycle.ferry_cost = Some(ferry_cost);
122 self
123 }
124 /// This value indicates the willingness to take ferries.
125 ///
126 /// This is a range of values between `0` and `1`:
127 /// - Values near `0` attempt to avoid ferries and
128 /// - values near `1` will favor ferries.
129 ///
130 /// **Note:** sometimes ferries are required to complete a route so values of `0` are not guaranteed to avoid ferries entirely.
131 ///
132 /// Default: `0.5`
133 pub fn use_ferry(mut self, use_ferry: f32) -> Self {
134 debug_assert!(use_ferry >= 0.0);
135 debug_assert!(use_ferry <= 1.0);
136 self.motorcycle.use_ferry = Some(use_ferry);
137 self
138 }
139 /// This value indicates the willingness to take highways.
140 ///
141 /// This is a range of values between `0` and 1:
142 /// - Values near `0` attempt to avoid highways and
143 /// - values near `1` will favor highways.
144 ///
145 /// **Note:** sometimes highways are required to complete a route so values of `0` are not guaranteed to avoid highways entirely.
146 ///
147 /// Default: `1.0`
148 pub fn use_highways(mut self, use_highways: f32) -> Self {
149 debug_assert!(use_highways >= 0.0);
150 debug_assert!(use_highways <= 1.0);
151 self.motorcycle.use_highways = Some(use_highways);
152 self
153 }
154 /// This value indicates the willingness to take roads with tolls.
155 ///
156 /// This is a range of values between `0` and 1:
157 /// - Values near `0` attempt to avoid tolls and
158 /// - values near `1` will not attempt to avoid them.
159 ///
160 /// **Note:** sometimes roads with tolls are required to complete a route so values of `0` are not guaranteed to avoid them entirely.
161 ///
162 /// Default: `0.5`
163 pub fn use_tolls(mut self, use_tolls: f32) -> Self {
164 debug_assert!(use_tolls >= 0.0);
165 debug_assert!(use_tolls <= 1.0);
166 self.motorcycle.use_tolls = Some(use_tolls);
167 self
168 }
169 /// This value indicates the willingness to take living streets.
170 ///
171 /// This is a range of values between `0` and 1:
172 /// - Values near `0` attempt to avoid living streets and
173 /// - values near `1` will favor living streets.
174 ///
175 /// **Note:** sometimes living streets are required to complete a route so values of `0` are not guaranteed to avoid living streets entirely.
176 ///
177 /// Default:
178 /// - `truck`: `0`
179 /// - `cars`/`buses`/`motor scooters`/`motorcycles`: `0.1`
180 pub fn use_living_streets(mut self, use_living_streets: f32) -> Self {
181 debug_assert!(use_living_streets >= 0.0);
182 debug_assert!(use_living_streets <= 1.0);
183 self.motorcycle.use_living_streets = Some(use_living_streets);
184 self
185 }
186 /// This value indicates the willingness to take track roads.
187 ///
188 /// This is a range of values between `0` and 1:
189 /// - Values near `0` attempt to avoid tracks and
190 /// - values near `1` will favor tracks a little bit.
191 ///
192 /// **Note:** sometimes tracks are required to complete a route so values of `0` are not guaranteed to avoid tracks entirely.
193 ///
194 /// Default:
195 /// - `0` for autos,
196 /// - `0.5` for motor scooters and motorcycles.
197 pub fn use_tracks(mut self, use_tracks: f32) -> Self {
198 debug_assert!(use_tracks >= 0.0);
199 debug_assert!(use_tracks <= 1.0);
200 self.motorcycle.use_tracks = Some(use_tracks);
201 self
202 }
203 /// A penalty applied for transition to generic service road.
204 ///
205 /// Default:
206 /// - `0` trucks and
207 /// - `15` for cars, buses, motor scooters and motorcycles.
208 pub fn service_penalty(mut self, service_penalty: f32) -> Self {
209 self.motorcycle.service_penalty = Some(service_penalty);
210 self
211 }
212 /// A factor that modifies (multiplies) the cost when generic service roads are encountered.
213 ///
214 /// Default: `1`
215 pub fn service_factor(mut self, service_factor: f32) -> Self {
216 self.motorcycle.service_factor = Some(service_factor);
217 self
218 }
219 /// A cost applied when encountering an international border.
220 ///
221 /// This cost is added to the estimated and elapsed times.
222 ///
223 /// Default: `600` seconds
224 pub fn country_crossing_cost(mut self, country_crossing_cost: f32) -> Self {
225 self.motorcycle.country_crossing_cost = Some(country_crossing_cost);
226 self
227 }
228 /// A penalty applied for a country crossing.
229 ///
230 /// This penalty can be used to create paths that avoid spanning country boundaries.
231 ///
232 /// Default: `0`
233 pub fn country_crossing_penalty(mut self, country_crossing_penalty: f32) -> Self {
234 self.motorcycle.country_crossing_penalty = Some(country_crossing_penalty);
235 self
236 }
237 /// Changes the metric to quasi-shortest, i.e. **purely distance-based costing**.
238 ///
239 /// Disables ALL other costings & penalties.
240 /// Also note, shortest will not disable hierarchy pruning, leading to potentially sub-optimal
241 /// routes for some costing models.
242 ///
243 /// Default: `false`
244 pub fn only_consider_quasi_shortest(mut self) -> Self {
245 self.motorcycle.shortest = Some(true);
246 self
247 }
248
249 /// A factor that allows controlling the contribution of distance and time to the route costs.
250 ///
251 /// The value is in range between `0` and 1, where
252 /// - `0` only takes time into account (default),
253 /// - `0.5` will weight them roughly equally
254 /// - `1` only distance.
255 ///
256 /// **Note:** this costing is currently only available for [`super::Costing::Auto`].
257 pub fn use_distance(mut self, use_distance: f32) -> Self {
258 debug_assert!(use_distance >= 0.0);
259 debug_assert!(use_distance <= 1.0);
260 self.motorcycle.use_distance = Some(use_distance);
261 self
262 }
263 /// Disable hierarchies to calculate the actual optimal route.
264 ///
265 /// **Note:** This could be quite a performance drainer so there is an upper limit of distance.
266 /// If the upper limit is exceeded, this option will always be `false`.
267 ///
268 /// Default: `false`
269 pub fn disable_hierarchy_pruning(mut self) -> Self {
270 self.motorcycle.disable_hierarchy_pruning = Some(true);
271 self
272 }
273 /// Top speed the vehicle can go.
274 ///
275 /// Also used to avoid roads with higher speeds than this value.
276 /// Must be between `10` and `252 KPH`.
277 ///
278 /// Default:
279 /// - `truck`: `120 KPH`
280 /// - `auto`/`bus`: `140 KPH`
281 pub fn top_speed(mut self, top_speed: f32) -> Self {
282 debug_assert!(top_speed >= 10.0);
283 debug_assert!(top_speed <= 252.0);
284 self.motorcycle.top_speed = Some(top_speed);
285 self
286 }
287 /// Fixed speed the vehicle can go. Used to override the calculated speed.
288 ///
289 /// Can be useful if speed of vehicle is known.
290 /// Must be between `1` and `252 KPH`.
291 ///
292 /// Default: `0KPH` which disables fixed speed and falls back to the standard calculated speed
293 /// based on the road attribution.
294 pub fn fixed_speed(mut self, fixed_speed: u32) -> Self {
295 debug_assert!(fixed_speed >= 1);
296 debug_assert!(fixed_speed <= 252);
297 self.motorcycle.fixed_speed = Some(fixed_speed);
298 self
299 }
300 /// A factor that penalizes the cost when traversing a closed edge
301 ///
302 /// Example:
303 /// If `search_filter.exclude_closures` is `false` for origin and/or destination
304 /// location and the route starts/ends on closed edges.
305 ///
306 /// Its value can range from
307 /// - `1.0` don't penalize closed edges,
308 /// - to `10.0` apply high cost penalty to closed edges.
309 ///
310 /// **Note:** This factor is applicable only for motorized modes of transport, i.e `auto`, `motorcycle`, `motor_scooter`, `bus`, `truck` & `taxi`.
311 ///
312 /// Default: `9.0`
313 pub fn closure_factor(mut self, closure_factor: f32) -> Self {
314 self.motorcycle.closure_factor = Some(closure_factor);
315 self
316 }
317 /// If set ignores all closures, marked due to live traffic closures, during routing.
318 ///
319 /// **Note:** This option cannot be set if `location.search_filter.exclude_closures` is also
320 /// specified in the request and will return an error if it is
321 pub fn ignore_closures(mut self) -> Self {
322 self.motorcycle.ignore_closures = Some(true);
323 self
324 }
325 /// If set, ignores any restrictions (e.g. turn/dimensional/conditional restrictions).
326 ///
327 /// Especially useful for matching GPS traces to the road network regardless of restrictions.
328 ///
329 /// Default: `false`
330 pub fn ignore_restrictions(mut self) -> Self {
331 self.motorcycle.ignore_restrictions = Some(true);
332 self
333 }
334 /// If set, ignores one-way restrictions.
335 ///
336 /// Especially useful for matching GPS traces to the road network ignoring uni-directional traffic rules.
337 /// Not included in [`Self::ignore_restrictions`] option.
338 ///
339 /// Default: `false`
340 pub fn ignore_oneways(mut self) -> Self {
341 self.motorcycle.ignore_oneways = Some(true);
342 self
343 }
344 /// Similar to [`Self::ignore_restrictions`], but will respect restrictions that impact vehicle safety,
345 /// such as weight and size restrictions.
346 ///
347 /// Default: `false`
348 pub fn ignore_non_vehicular_restrictions(mut self) -> Self {
349 self.motorcycle.ignore_non_vehicular_restrictions = Some(true);
350 self
351 }
352 /// Ignore mode-specific access tags.
353 ///
354 /// Especially useful for matching GPS traces to the road network regardless of restrictions.
355 ///
356 /// Default `false`
357 pub fn ignore_access(mut self) -> Self {
358 self.motorcycle.ignore_access = Some(true);
359 self
360 }
361 /// Will determine which speed sources are used, if available.
362 ///
363 /// A list of strings with the following possible values:
364 /// - [`UsedSpeedSources::All`]
365 /// - [`UsedSpeedSources::Freeflow`]
366 /// - [`UsedSpeedSources::Constrained`]
367 /// - [`UsedSpeedSources::Predicted`]
368 /// - [`UsedSpeedSources::Current`]
369 ///
370 /// Default: [`UsedSpeedSources::All`] sources (again, only if available)
371 pub fn speed_types(mut self, speed_types: UsedSpeedSources) -> Self {
372 if speed_types == UsedSpeedSources::All {
373 self.motorcycle.speed_types = None
374 } else {
375 self.motorcycle.speed_types = Some(speed_types);
376 }
377 self
378 }
379
380 /// The height of the vehicle (in meters).
381 ///
382 /// Default:
383 /// - `car`/`bus`/`taxi`: `1.9` and
384 /// - `truck`: `4.11`
385 pub fn height(mut self, height: f32) -> Self {
386 self.motorcycle.height = Some(height);
387 self
388 }
389 /// The width of the vehicle (in meters).
390 ///
391 /// Default:
392 /// - `car`/`bus`/`taxi`: `1.6` and
393 /// - `truck`: `2.6`
394 pub fn width(mut self, width: f32) -> Self {
395 self.motorcycle.width = Some(width);
396 self
397 }
398 /// Exclude unpaved roads.
399 ///
400 /// If exclude_unpaved is set it is allowed to start and end with unpaved roads,
401 /// but is not allowed to have them in the middle of the route path,
402 /// otherwise they are allowed.
403 ///
404 /// Default: `false`.
405 pub fn exclude_unpaved(mut self) -> Self {
406 self.motorcycle.exclude_unpaved = Some(true);
407 self
408 }
409 /// Desire to avoid routes with cash-only tolls.
410 ///
411 /// Default: `false`.
412 pub fn exclude_cash_only_tolls(mut self, exclude_cash_only_tolls: bool) -> Self {
413 self.motorcycle.exclude_cash_only_tolls = Some(exclude_cash_only_tolls);
414 self
415 }
416 /// Include HOV roads with a 2-occupant requirement in the route when advantageous.
417 ///
418 /// Default: `false`.
419 pub fn include_hov2(mut self, include_hov2: bool) -> Self {
420 self.motorcycle.include_hov2 = Some(include_hov2);
421 self
422 }
423 /// Include HOV roads with a 3-occupant requirement in the route when advantageous.
424 ///
425 /// Default: `false`.
426 pub fn include_hov3(mut self, include_hov3: bool) -> Self {
427 self.motorcycle.include_hov3 = Some(include_hov3);
428 self
429 }
430 /// Include tolled HOV roads which require the driver to pay a toll if the occupant requirement isn't met.
431 ///
432 /// Default: `false`.
433 pub fn include_hot(mut self, include_hot: bool) -> Self {
434 self.motorcycle.include_hot = Some(include_hot);
435 self
436 }
437 /// Desire for adventure in a routes.
438 ///
439 /// This is a range of values between `0` and `1`:
440 /// - Values near `0` attempt to avoid trails, tracks, unclassified or bad surfaces and
441 /// - values near `1` will ftend to avoid major roads and route on secondary roads.
442 ///
443 /// Default: `0.0`.
444 pub fn use_trails(mut self, use_trails: f32) -> Self {
445 self.motorcycle.use_trails = Some(use_trails);
446 self
447 }
448}
449
450#[derive(Serialize, Debug, Clone, Copy, PartialEq, Eq)]
451/// The speed sources that can be used for routing.
452pub enum UsedSpeedSources {
453 #[serde(rename = "all")]
454 /// All available speed sources.
455 All,
456 #[serde(rename = "freeflow")]
457 /// Freeflow speed.
458 Freeflow,
459 #[serde(rename = "constrained")]
460 /// Constrained speed.
461 Constrained,
462 #[serde(rename = "predicted")]
463 /// Predicted speed.
464 Predicted,
465 #[serde(rename = "current")]
466 /// Current speed.
467 Current,
468}
469
470#[cfg(test)]
471mod test {
472 use super::*;
473 #[test]
474 fn serialisation() {
475 assert_eq!(
476 serde_json::to_value(MotorcycleCostingOptions::default()).unwrap(),
477 serde_json::json!({"motorcycle":{}})
478 );
479 }
480}