Skip to main content

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}