valhalla_client/route.rs
1use crate::costing;
2pub use crate::shapes::ShapePoint;
3pub use crate::DateTime;
4use serde::{Deserialize, Serialize};
5
6#[derive(Deserialize, Debug, Clone)]
7/// Response from the Valhalla route service
8pub(crate) struct Response {
9 pub(crate) trip: Trip,
10}
11
12#[derive(Deserialize, Debug, Clone)]
13/// Description of a trip
14pub struct Trip {
15 /// Status code
16 pub status: i32,
17 /// Status message
18 pub status_message: String,
19 /// The via [`Manifest::units`] specified units of length are returned.
20 ///
21 /// Either [`super::Units::Metric`] or [`super::Units::Imperial`].
22 pub units: super::Units,
23 /// The language of the narration instructions.
24 ///
25 /// If the user specified a language via [`Manifest::language`] in the directions options and the specified language was supported.
26 /// This returned value will be equal to the specified value.
27 /// Otherwise, this value will be the default (`en-US`) language.
28 pub language: String,
29 /// Location information is returned in the same form as it is entered.
30 ///
31 /// Additional fields are added to indicate the side of the street.
32 /// Output can be changed via via [`Manifest::locations`].
33 pub locations: Vec<Location>,
34 /// This array may contain warning objects informing about deprecated request parameters, clamped values etc.
35 pub warnings: Option<Vec<String>>,
36 /// Name of your route request.
37 ///
38 /// If an id is specified via [`Manifest::id`], the naming will be sent thru to the response.
39 pub id: Option<String>,
40 /// List of [`Leg`]s constituting a [`Trip`]
41 pub legs: Vec<Leg>,
42 /// Basic information about the entire [`Trip`]
43 pub summary: Summary,
44}
45#[cfg(feature = "gpx")]
46impl From<Trip> for gpx::Gpx {
47 fn from(trip: Trip) -> Self {
48 let mut gpx = Self {
49 version: gpx::GpxVersion::Gpx11,
50 creator: Some("valhalla".to_string()),
51 ..Default::default()
52 };
53 let track = gpx::Track {
54 name: Some("route".to_string()),
55 segments: trip.legs.iter().map(|leg| leg.into()).collect(),
56 ..Default::default()
57 };
58 gpx.tracks.push(track);
59
60 let ps = trip
61 .legs
62 .iter()
63 .flat_map(|leg| {
64 leg.maneuvers.iter().map(|m| {
65 let p = &leg.shape[m.begin_shape_index];
66
67 gpx::Waypoint::new(p.into())
68 })
69 })
70 .collect();
71 let route = gpx::Route {
72 name: Some("route".to_string()),
73 points: ps,
74 ..Default::default()
75 };
76 gpx.routes.push(route);
77 gpx
78 }
79}
80#[derive(Deserialize, Debug, Clone)]
81/// Summary information about the entire trip
82pub struct Summary {
83 /// Estimated elapsed time in seconds
84 pub time: f64,
85 /// Distance traveled
86 ///
87 /// Unit is either [`super::Units::Metric`] or [`super::Units::Imperial`] and specified in [`Trip`] for clarification.
88 /// See [`Manifest::units`] to change the units.
89 pub length: f64,
90 /// If the path uses one or more toll segments
91 pub has_toll: bool,
92 /// If the path uses one or more highway segments
93 pub has_highway: bool,
94 /// if the path uses one or more ferry segments
95 pub has_ferry: bool,
96 /// Minimum latitude of the sections' bounding box
97 pub min_lat: f64,
98 /// Minimum longitude of the sections' bounding box
99 pub min_lon: f64,
100 /// Maximum latitude of the sections' bounding box
101 pub max_lat: f64,
102 /// Maximum longitude of the sections' bounding box
103 pub max_lon: f64,
104 /// List of level change-events (i.e. when navigating inside a building)
105 /// An event is `(shape_index, level)`
106 ///
107 /// Can be used to split up the geometry along the level changes.
108 pub level_changes: Option<Vec<(usize, f32)>>,
109}
110
111#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
112/// Travel mode
113pub enum TravelMode {
114 #[serde(rename = "drive")]
115 /// Drive (car, motorcycle, truck, motor scooter)
116 Drive,
117 #[serde(rename = "pedestrian")]
118 /// Pedestrian (walking)
119 Pedestrian,
120 #[serde(rename = "bicycle")]
121 /// Bicycle (bike)
122 Bicycle,
123 #[serde(rename = "transit")]
124 /// Transit (bus, tram, metro, rail, ferry, cable car, gondola, funicular)
125 Transit,
126}
127
128#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
129#[serde(untagged)]
130/// Travel type
131pub enum TravelType {
132 /// Drive
133 Drive(DriveTravelType),
134 /// Pedestrian
135 Pedestrian(costing::pedestrian::PedestrianType),
136 /// Bicycle
137 Bicycle(costing::bicycle::BicycleType),
138 /// Transit
139 Transit(TransitTravelType),
140}
141
142#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
143/// Drive travel type
144pub enum DriveTravelType {
145 #[serde(rename = "car")]
146 /// Car
147 Car,
148 #[serde(rename = "motorcycle")]
149 /// Motorcycle
150 Motorcycle,
151 #[serde(rename = "truck")]
152 /// Truck
153 Truck,
154 #[serde(rename = "motor_scooter")]
155 /// Motor scooter
156 MotorScooter,
157}
158
159#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
160/// Transit travel type
161pub enum TransitTravelType {
162 #[serde(rename = "tram")]
163 /// Tram
164 Tram,
165 #[serde(rename = "metro")]
166 /// Metro
167 Metro,
168 #[serde(rename = "rail")]
169 /// Rail
170 Rail,
171 #[serde(rename = "bus")]
172 /// Bus
173 Bus,
174 #[serde(rename = "ferry")]
175 /// Ferry
176 Ferry,
177 #[serde(rename = "cable_car")]
178 /// Cable car
179 CableCar,
180 #[serde(rename = "gondola")]
181 /// Gondola
182 Gondola,
183 #[serde(rename = "funicular")]
184 /// Funicular
185 Funicular,
186}
187
188#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
189/// Bike share maneuver type
190pub enum BssManeuverType {
191 #[serde(rename = "NoneAction")]
192 /// No action
193 NoneAction,
194 #[serde(rename = "RentBikeAtBikeShare")]
195 /// Rent bike at bike share
196 RentBikeAtBikeShare,
197 #[serde(rename = "ReturnBikeAtBikeShare")]
198 /// Return bike at bike share
199 ReturnBikeAtBikeShare,
200}
201
202#[derive(Deserialize, Debug, Clone)]
203/// A leg is a section of the route between two locations.
204pub struct Leg {
205 /// Summary information about the leg
206 pub summary: Summary,
207
208 /// Maneuver information
209 #[serde(default)]
210 pub maneuvers: Vec<Maneuver>,
211
212 /// The shape of the leg
213 #[serde(deserialize_with = "crate::shapes::deserialize_shape")]
214 pub shape: Vec<ShapePoint>,
215}
216
217#[cfg(feature = "gpx")]
218impl From<&Leg> for gpx::TrackSegment {
219 fn from(leg: &Leg) -> Self {
220 Self {
221 points: leg.shape[leg.maneuvers[0].begin_shape_index
222 ..leg.maneuvers[leg.maneuvers.len() - 1].end_shape_index]
223 .iter()
224 .map(|location| gpx::Waypoint::new(location.into()))
225 .collect(),
226 }
227 }
228}
229
230#[derive(serde_repr::Deserialize_repr, Debug, Clone, Copy, PartialEq, Eq)]
231#[allow(missing_docs)]
232#[repr(i8)]
233/// The type of maneuver
234pub enum ManeuverType {
235 /// No maneuver
236 None = 0,
237 Start,
238 StartRight,
239 StartLeft,
240 Destination,
241 DestinationRight,
242 DestinationLeft,
243 Becomes,
244 Continue,
245 SlightRight,
246 Right,
247 SharpRight,
248 UturnRight,
249 UturnLeft,
250 SharpLeft,
251 Left,
252 SlightLeft,
253 RampStraight,
254 RampRight,
255 RampLeft,
256 ExitRight,
257 ExitLeft,
258 StayStraight,
259 StayRight,
260 StayLeft,
261 Merge,
262 RoundaboutEnter,
263 RoundaboutExit,
264 FerryEnter,
265 FerryExit,
266 Transit,
267 TransitTransfer,
268 TransitRemainOn,
269 TransitConnectionStart,
270 TransitConnectionTransfer,
271 TransitConnectionDestination,
272 PostTransitConnectionDestination,
273 MergeRight,
274 MergeLeft,
275 ElevatorEnter,
276 StepsEnter,
277 EscalatorEnter,
278 BuildingEnter,
279 BuildingExit,
280}
281
282#[derive(Deserialize, Default, Clone, Debug)]
283#[serde(default)]
284/// A sign is a collection of elements that are used to describe the exit number, exit branch, exit
285/// toward, and exit name.
286pub struct Sign {
287 /// list of exit number elements.
288 ///
289 /// If an exit number element exists, it is typically just one value
290 ///
291 /// Example: `91B`
292 pub exit_number_elements: Vec<ManeuverSignElement>,
293 /// Exit branch elements.
294 ///
295 /// The exit branch element text is the subsequent road name or route number after the sign
296 ///
297 /// Example: `I 95 North`
298 pub exit_branch_elements: Vec<ManeuverSignElement>,
299 /// Exit toward elements.
300 ///
301 /// The exit toward element text is the location where the road ahead goes.
302 /// The location is typically a control city, but may also be a future road name or route number.
303 ///
304 /// Example: `New York`
305 pub exit_toward_elements: Vec<ManeuverSignElement>,
306 /// Exit name elements.
307 ///
308 /// The exit name element is the interchange identifier.
309 /// Typically not used in the US.
310 ///
311 /// Example: `Gettysburg Pike`
312 pub exit_name_elements: Vec<ManeuverSignElement>,
313}
314
315#[derive(Deserialize, Clone, Debug)]
316/// A sign element is a single text string that is part of a sign.
317pub struct ManeuverSignElement {
318 /// Interchange sign text.
319 ///
320 /// Examples:
321 /// - exit number: `91B`
322 /// - exit branch: `I 95 North`
323 /// - exit toward: `New York`
324 /// - exit name: `Gettysburg Pike`
325 pub text: String,
326 /// The frequency of this sign element within a set a consecutive signs
327 pub consecutive_count: Option<usize>,
328}
329
330#[derive(Deserialize, Clone, Debug)]
331/// A maneuver is a single instruction to the user.
332pub struct Maneuver {
333 /// Type of maneuver
334 #[serde(rename = "type")]
335 pub type_: ManeuverType,
336 /// Written maneuver instruction, describing the maneuver.
337 ///
338 /// Example: "Turn right onto Main Street".
339 pub instruction: String,
340
341 /// Text suitable for use as a verbal alert in a navigation application.
342 ///
343 /// The transition alert instruction will prepare the user for the forthcoming transition.
344 ///
345 /// Example: "Turn right onto North Prince Street"
346 pub verbal_transition_alert_instruction: Option<String>,
347
348 /// Text suitable for use as a verbal message immediately prior to the maneuver transition.
349 ///
350 /// Example: "Turn right onto North Prince Street, U.S. 2 22"
351 pub verbal_pre_transition_instruction: Option<String>,
352 /// Text suitable for use as a verbal message immediately after the maneuver transition.
353 ///
354 /// Example: "Continue on U.S. 2 22 for 3.9 miles"
355 pub verbal_post_transition_instruction: Option<String>,
356
357 /// List of street names that are consistent along the entire nonobvious maneuver
358 pub street_names: Option<Vec<String>>,
359
360 /// When present, these are the street names at the beginning (transition point) of the
361 /// nonobvious maneuver (if they are different than the names that are consistent along the
362 /// entire nonobvious maneuver).
363 pub begin_street_names: Option<Vec<String>>,
364 /// Estimated time along the maneuver in seconds.
365 pub time: f64,
366 /// Maneuver length in the [`super::Units`] specified via [`Manifest::units`]
367 pub length: f64,
368 /// Index into the list of shape points for the start of the maneuver.
369 pub begin_shape_index: usize,
370 /// Index into the list of shape points for the end of the maneuver.
371 pub end_shape_index: usize,
372 /// `true` if a toll booth is encountered on this maneuver.
373 pub toll: Option<bool>,
374 /// `true` if a highway is encountered on this maneuver.
375 pub highway: Option<bool>,
376 /// `true` if the maneuver is unpaved or rough pavement, or has any portions that have rough
377 /// pavement.
378 pub rough: Option<bool>,
379 /// `true` if a gate is encountered on this maneuver.
380 pub gate: Option<bool>,
381 /// `true` if a ferry is encountered on this maneuver.
382 pub ferry: Option<bool>,
383 /// Contains the interchange guide information at a road junction associated with this
384 /// maneuver.
385 ///
386 /// See [`Sign`] for details.
387 pub sign: Option<Sign>,
388 /// The spoke to exit roundabout after entering.
389 pub roundabout_exit_count: Option<i64>,
390 /// Written depart time instruction.
391 ///
392 /// Typically used with a transit maneuver, such as "Depart: 8:04 AM from 8 St - NYU".
393 pub depart_instruction: Option<String>,
394 /// Text suitable for use as a verbal depart time instruction.
395 ///
396 /// Typically used with a transit maneuver, such as "Depart at 8:04 AM from 8 St - NYU".
397 pub verbal_depart_instruction: Option<String>,
398 /// Written arrive time instruction.
399 ///
400 /// Typically used with a transit maneuver, such as "Arrive: 8:10 AM at 34 St - Herald Sq".
401 pub arrive_instruction: Option<String>,
402 /// Text suitable for use as a verbal arrive time instruction.
403 ///
404 /// Typically used with a transit maneuver, such as "Arrive at 8:10 AM at 34 St - Herald Sq".
405 pub verbal_arrive_instruction: Option<String>,
406 /// Contains the attributes that describe a specific transit route.
407 ///
408 /// See [`TransitInfo`] for details.
409 pub transit_info: Option<TransitInfo>,
410 /// `true` if [`Self::verbal_pre_transition_instruction`] has been appended with
411 /// the verbal instruction of the next maneuver and thus contains more than one instruction.
412 pub verbal_multi_cue: Option<bool>,
413 /// Travel mode
414 pub travel_mode: TravelMode,
415 /// Travel type
416 pub travel_type: TravelType,
417 /// Describes bike share maneuver.
418 ///
419 /// Used when travel_mode is [`TravelMode::Bicycle`].
420 ///
421 /// Default: [`BssManeuverType::NoneAction`]
422 pub bss_maneuver_type: Option<BssManeuverType>,
423}
424
425#[derive(Deserialize, Debug, Clone)]
426/// Transit information
427pub struct TransitInfo {
428 /// Global transit route identifier.
429 pub onestop_id: String,
430 /// Short name describing the transit route
431 ///
432 /// Example: "N"
433 pub short_name: String,
434 /// Long name describing the transit route
435 ///
436 /// Example: "Broadway Express"
437 pub long_name: String,
438 /// The sign on a public transport vehicle that identifies the route destination to passengers.
439 ///
440 /// Example: "ASTORIA - DITMARS BLVD"
441 pub headsign: String,
442 /// The numeric color value associated with a transit route.
443 ///
444 /// The value for yellow would be "16567306".
445 pub color: i32,
446 /// The numeric text color value associated with a transit route.
447 ///
448 /// The value for black would be "0".
449 pub text_color: String,
450 /// The description of the transit route
451 ///
452 /// Example: "Trains operate from Ditmars Boulevard, Queens, to Stillwell Avenue, Brooklyn, at all times
453 /// N trains in Manhattan operate along Broadway and across the Manhattan Bridge to and from Brooklyn.
454 /// Trains in Brooklyn operate along 4th Avenue, then through Borough Park to Gravesend.
455 /// Trains typically operate local in Queens, and either express or local in Manhattan and Brooklyn,
456 /// depending on the time. Late night trains operate via Whitehall Street, Manhattan.
457 /// Late night service is local"
458 pub description: String,
459 /// Global operator/agency identifier.
460 pub operator_onestop_id: String,
461 /// Operator/agency name
462 ///
463 /// Short name is used over long name.
464 ///
465 /// Example: "BART", "King County Marine Division", and so on.
466 pub operator_name: String,
467 /// Operator/agency URL
468 ///
469 /// Example: `http://web.mta.info/`.
470 pub operator_url: String,
471 /// A list of the stops/stations associated with a specific transit route.
472 ///
473 /// See [`TransitStop`] for details.
474 pub transit_stops: Vec<TransitStop>,
475}
476
477#[derive(serde_repr::Deserialize_repr, Debug, Clone, Copy, PartialEq, Eq)]
478#[repr(u8)]
479/// Transit stop type
480pub enum TransitStopType {
481 /// Simple stop.
482 Stop = 0,
483 /// Station.
484 Station,
485}
486
487#[derive(Deserialize, Debug, Clone)]
488/// Transit stop information
489pub struct TransitStop {
490 #[serde(rename = "type")]
491 /// The type of transit stop
492 pub type_: TransitStopType,
493 /// Name of the stop or station
494 ///
495 /// Example: "14 St - Union Sq"
496 pub name: String,
497 /// Arrival date and time
498 pub arrival_date_time: chrono::NaiveDateTime,
499 /// Departure date and time
500 pub departure_date_time: chrono::NaiveDateTime,
501 /// `true` if this stop is a marked as a parent stop.
502 pub is_parent_stop: bool,
503 /// `true` if the times are based on an assumed schedule because the actual schedule is not
504 /// known.
505 pub assumed_schedule: bool,
506 /// Latitude of the transit stop in degrees.
507 pub lat: f64,
508 /// Longitude of the transit stop in degrees.
509 pub lon: f64,
510}
511
512#[derive(Serialize, Default, Debug, Clone, Copy, PartialEq, Eq)]
513/// Type of the directions
514pub enum DirectionsType {
515 /// indicating no maneuvers or instructions should be returned.
516 #[serde(rename = "none")]
517 None,
518
519 /// indicating that only maneuvers be returned.
520 #[serde(rename = "maneuvers")]
521 Maneuvers,
522
523 /// indicating that maneuvers with instructions should be returned (this is the default if not
524 /// specified).
525 #[default]
526 #[serde(rename = "instructions")]
527 Instructions,
528}
529
530#[serde_with::skip_serializing_none]
531#[derive(Serialize, Default, Debug)]
532/// Route request
533pub struct Manifest {
534 #[serde(flatten)]
535 costing: Option<costing::Costing>,
536 locations: Vec<Location>,
537 units: Option<super::Units>,
538 id: Option<String>,
539 language: Option<String>,
540 directions_type: Option<DirectionsType>,
541 alternates: Option<i32>,
542 exclude_locations: Option<Vec<Location>>,
543 exclude_polygons: Option<Vec<Vec<super::Coordinate>>>,
544 linear_references: Option<bool>,
545 prioritize_bidirectional: Option<bool>,
546 roundabout_exits: Option<bool>,
547 date_time: Option<DateTime>,
548}
549
550impl Manifest {
551 #[must_use]
552 /// Create a new [`Manifest`] builder
553 pub fn builder() -> Self {
554 Self::default()
555 }
556 /// Configures the costing model
557 ///
558 /// Valhalla's routing service uses dynamic, run-time costing to generate the route path.
559 /// Can be configured with different settings depending on the costing model used.
560 ///
561 /// Default: [`costing::Costing::Auto`]
562 pub fn costing(mut self, costing: costing::Costing) -> Self {
563 self.costing = Some(costing);
564 self
565 }
566
567 /// Specify locations to visit as an ordered list
568 ///
569 /// Minimum number of locations: 2
570 ///
571 /// A location must include a latitude and longitude in decimal degrees.
572 /// The coordinates can come from many input sources, such as a GPS location, a point or a
573 /// click on a map, a geocoding service, and so on.
574 ///
575 /// **Note:** Valhalla cannot search for names or addresses or perform geocoding or reverse geocoding.
576 /// External search services, such as [Mapbox Geocoding](https://www.mapbox.com/api-documentation/#geocoding),
577 /// can be used to find places and geocode addresses, which must be converted to coordinates for input.
578 ///
579 /// To build a route, you need to specify two [`LocationType::Break`] locations.
580 /// In addition, you can include [`LocationType::Through`], [`LocationType::Via`] or
581 /// [`LocationType::BreakThrough`] locations to influence the route path.
582 /// See [`LocationType`] for further information.
583 pub fn locations(mut self, locations: impl IntoIterator<Item = Location>) -> Self {
584 self.locations = locations.into_iter().collect();
585 debug_assert!(self.locations.len() >= 2);
586 self
587 }
588
589 /// Sets the distance units for output.
590 ///
591 /// Possible unit types are
592 /// - miles via [`super::Units::Imperial`] and
593 /// - kilometers via [`super::Units::Metric`].
594 ///
595 /// Default: [`super::Units::Metric`]
596 pub fn units(mut self, units: super::Units) -> Self {
597 self.units = Some(units);
598 self
599 }
600
601 /// Name of the route request
602 ///
603 /// If id is specified, the naming will be sent through to the response.
604 pub fn id(mut self, id: impl ToString) -> Self {
605 self.id = Some(id.to_string());
606 self
607 }
608
609 /// The language of the narration instructions based on the
610 /// [IETF BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) language tag string.
611 ///
612 /// If unsupported, the language `en-US` (United States-based English) is used
613 /// Currently supported language list can be found here:
614 /// <https://valhalla.github.io/valhalla/api/turn-by-turn/api-reference/#supported-language-tags>
615 ///
616 /// Default: `en-US` (United States-based English)
617 pub fn language(mut self, language: impl ToString) -> Self {
618 self.language = Some(language.to_string());
619 self
620 }
621 /// Sets the directions type
622 ///
623 /// [`DirectionsType`] is an enum with 3 values:
624 /// - [`DirectionsType::None`] indicates no maneuvers or instructions should be returned.
625 /// - [`DirectionsType::Maneuvers`] indicates that only maneuvers be returned.
626 /// - [`DirectionsType::Instructions`] indicates that maneuvers with instructions should be returned
627 ///
628 /// Default: [`DirectionsType::Instructions`]
629 pub fn directions_type(mut self, directions_type: DirectionsType) -> Self {
630 self.directions_type = Some(directions_type);
631 self
632 }
633
634 /// How many alternate routes should be provided
635 ///
636 /// There may be no alternates or fewer alternates than the user specifies.
637 ///
638 /// Alternates are not yet supported on
639 /// - multipoint routes (i.e. routes with more than 2 locations) and
640 /// - time dependent routes
641 pub fn alternates(mut self, alternates: i32) -> Self {
642 self.alternates = Some(alternates);
643 self
644 }
645
646 /// A set of [`Location`]s to exclude or avoid within a route
647 ///
648 /// They are mapped to the closest road or roads and these roads are excluded
649 /// from the route path computation.
650 pub fn exclude_locations(
651 mut self,
652 exclude_locations: impl IntoIterator<Item = Location>,
653 ) -> Self {
654 self.exclude_locations = Some(exclude_locations.into_iter().collect());
655 self
656 }
657
658 /// Sets at least one exterior rings of excluded polygons.
659 ///
660 /// **Note:** Contrary to [`Self::exclude_polygon`], this OVERRIDES previously set excluded polygons.
661 ///
662 /// Roads intersecting these rings will be avoided during path finding.
663 /// If you only need to avoid a few specific roads, it's much more efficient to use
664 /// [`Self::exclude_locations`].
665 /// Valhalla will close open rings (i.e. copy the first coordinate to the last position).
666 ///
667 /// # Example:
668 /// ```rust,no_run
669 /// use valhalla_client::blocking::Valhalla;
670 /// use valhalla_client::route::{Location, Manifest};
671 /// use valhalla_client::costing::{Costing};
672 ///
673 /// let polygon_around_midrecht_between_amsterdam_and_utrecht = vec![(4.9904022, 52.2528761), (4.8431168, 52.2392163), (4.8468933, 52.1799052), (4.9845657, 52.2102016), (4.9904022, 52.2528761)];
674 /// let polygon_around_leiden = vec![(4.5891266, 52.1979985),(4.4105987, 52.2560249),(4.3034820, 52.1592721),(4.5005493, 52.0935286),(4.5726471, 52.1373684),(4.5898132, 52.1984193),(4.5891266, 52.1979985)];
675 /// let amsterdam = Location::new(4.9041, 52.3676);
676 /// let utrecht = Location::new(5.1214, 52.0907);
677 ///
678 /// let manifest = Manifest::builder()
679 /// .locations([amsterdam, utrecht])
680 /// .exclude_polygons([polygon_around_leiden, polygon_around_midrecht_between_amsterdam_and_utrecht])
681 /// .costing(Costing::MotorScooter(Default::default()));
682 ///
683 /// let response = Valhalla::default()
684 /// .route(manifest)
685 /// .unwrap();
686 /// # assert!(!response.legs.is_empty());
687 /// ```
688 pub fn exclude_polygons(
689 mut self,
690 exclude_polygons: impl IntoIterator<Item = impl IntoIterator<Item = super::Coordinate>>,
691 ) -> Self {
692 let new_excluded_polygons = exclude_polygons
693 .into_iter()
694 .map(|e| e.into_iter().collect())
695 .collect();
696 self.exclude_polygons = Some(new_excluded_polygons);
697 self
698 }
699 /// Add one exterior rings as an excluded polygon.
700 ///
701 /// **Note:** Contrary to [`Self::exclude_polygons`], this APPENDS to the previously set excluded polygons.
702 ///
703 /// Roads intersecting these rings will be avoided during path finding.
704 /// If you only need to avoid a few specific roads, it's much more efficient to use
705 /// exclude_locations.
706 /// Valhalla will close open rings (i.e. copy the first coordinate to the last position).
707 ///
708 /// # Example:
709 /// ```rust,no_run
710 /// use valhalla_client::blocking::Valhalla;
711 /// use valhalla_client::route::{Location, Manifest};
712 /// use valhalla_client::costing::{Costing};
713 ///
714 /// let polygon_around_leiden = vec![(4.5891266, 52.1979985),(4.4105987, 52.2560249),(4.3034820, 52.1592721),(4.5005493, 52.0935286),(4.5726471, 52.1373684),(4.5898132, 52.1984193),(4.5891266, 52.1979985)];
715 /// let amsterdam = Location::new(4.9041, 52.3676);
716 /// let utrecht = Location::new(5.1214, 52.0907);
717 ///
718 /// let manifest = Manifest::builder()
719 /// .locations([amsterdam, utrecht])
720 /// .exclude_polygon(polygon_around_leiden)
721 /// .costing(Costing::Auto(Default::default()));
722 ///
723 /// let response = Valhalla::default()
724 /// .route(manifest)
725 /// .unwrap();
726 /// # assert!(!response.legs.is_empty());
727 /// ```
728 pub fn exclude_polygon(
729 mut self,
730 exclude_polygon: impl IntoIterator<Item = super::Coordinate>,
731 ) -> Self {
732 let new_excluded_polygon = exclude_polygon.into_iter().collect();
733 if let Some(ref mut polygons) = self.exclude_polygons {
734 polygons.push(new_excluded_polygon);
735 } else {
736 self.exclude_polygons = Some(vec![new_excluded_polygon]);
737 }
738 self
739 }
740
741 /// When present and true, the successful route response will include a key `linear_references`.
742 ///
743 /// Its value is an array of base64-encoded [OpenLR location references](https://en.wikipedia.org/wiki/OpenLR),
744 /// one for each graph edge of the road network matched by the input trace.
745 #[doc(hidden)] // TODO: need to implement the linear_references field
746 pub fn include_linear_references(mut self) -> Self {
747 self.linear_references = Some(true);
748 self
749 }
750
751 /// Prioritize bidirectional A* when `date_time.type = depart_at/current`.
752 ///
753 /// Currently, it does not update the time (and speeds) when searching for the route path, but
754 /// the ETA on that route is recalculated based on the time-dependent speeds
755 ///
756 /// Default: time_dependent_forward A* is used in these cases, but bidirectional A* is much faster
757 pub fn prioritize_bidirectional(mut self) -> Self {
758 self.prioritize_bidirectional = Some(true);
759 self
760 }
761
762 /// Don't include instructions at roundabouts to the output
763 ///
764 /// Default: `true`
765 pub fn roundabout_exits(mut self) -> Self {
766 self.roundabout_exits = Some(false);
767 self
768 }
769 /// Shortcut for configuring the arrival/departure date_time settings globally
770 /// instead of specifying it for each of the [locations](Location::date_time).
771 ///
772 /// See [`Location::date_time`] if you want a more granular API.
773 pub fn date_time(mut self, date_time: DateTime) -> Self {
774 self.date_time = Some(date_time);
775 self
776 }
777}
778
779#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq)]
780/// Location type
781pub enum LocationType {
782 #[default]
783 #[serde(rename = "break")]
784 /// A location at which we allows u-turns and generate legs and arrival/departure maneuvers
785 Break,
786
787 #[serde(rename = "through")]
788 /// A location at which we neither allow u-turns nor generate legs or arrival/departure maneuvers
789 Through,
790
791 #[serde(rename = "via")]
792 /// A location at which we allow u-turns but do not generate legs or arrival/departure maneuvers
793 Via,
794
795 #[serde(rename = "break_through")]
796 /// A location at which we do not allow u-turns but do generate legs and arrival/departure maneuvers
797 BreakThrough,
798}
799
800#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq)]
801/// Side of the street
802pub enum Side {
803 #[serde(rename = "same")]
804 /// The location should be visited from the same side of the road
805 Same,
806
807 #[serde(rename = "opposite")]
808 /// The location should be visited from the opposite side of the road
809 Opposite,
810
811 #[default]
812 #[serde(rename = "either")]
813 /// The location should be visited from either side of the road
814 Either,
815}
816
817#[cfg(feature = "gpx")]
818impl From<&Location> for gpx::Waypoint {
819 fn from(location: &Location) -> Self {
820 let point =
821 geo_types::Point::new(f64::from(location.longitude), f64::from(location.latitude));
822 let mut p = Self::new(point);
823 p.name.clone_from(&location.name);
824 p
825 }
826}
827impl From<super::Coordinate> for Location {
828 fn from((latitude, longitude): super::Coordinate) -> Self {
829 Self {
830 latitude,
831 longitude,
832 ..Default::default()
833 }
834 }
835}
836
837impl Location {
838 /// Create a Location from latitude/longitude of the location in degrees.
839 ///
840 /// This is assumed to be both routing location and display location is equal.
841 /// See [`Self::display_coordinates`] to change the display location
842 pub fn new(longitude: f32, latitude: f32) -> Self {
843 Self {
844 latitude,
845 longitude,
846 ..Default::default()
847 }
848 }
849 /// Display Coordinate location in degrees.
850 ///
851 /// Will be used to determine the side of street.
852 /// Must be valid to achieve the desired effect.
853 pub fn display_coordinates(mut self, display_lat: f32, display_lon: f32) -> Self {
854 self.display_lat = Some(display_lat);
855 self.display_lon = Some(display_lon);
856 self
857 }
858
859 /// Sets the Street name.
860 ///
861 /// May be used to assist finding the correct routing location at the specified coordinate.
862 /// **This is not currently implemented.**
863 pub fn street_name(mut self, street: impl ToString) -> Self {
864 self.street = Some(street.to_string());
865 self
866 }
867
868 /// Sets the OpenStreetMap identification number for a polyline way.
869 ///
870 /// The way ID may be used to assist finding the correct routing location at the specified coordinate.
871 /// **This is not currently implemented.**
872 pub fn way_id(mut self, way_id: i64) -> Self {
873 self.way_id = Some(way_id);
874 self
875 }
876
877 /// Sets the Minimum number of nodes (intersections) reachable for a given edge (road between
878 /// intersections) to consider that edge as belonging to a connected region.
879 ///
880 /// When correlating this location to the route network, try to find candidates who are reachable
881 /// from this many or more nodes (intersections). If a given candidate edge reaches less than
882 /// this number of nodes it is considered to be a disconnected island, and we will search for more
883 /// candidates until we find at least one that isn't considered a disconnected island.
884 /// If this value is larger than the configured service limit it will be clamped to that limit.
885 ///
886 /// Default: `50` reachable nodes.
887 pub fn minimum_reachability(mut self, minimum_reachability: i32) -> Self {
888 self.minimum_reachability = Some(minimum_reachability);
889 self
890 }
891
892 /// The number of meters about this input location within which edges (roads between
893 /// intersections) will be considered as candidates for said location.
894 ///
895 /// When correlating this location to the route network, try to only return results within
896 /// this distance (meters) from this location. If there are no candidates within this distance
897 /// it will return the closest candidate within reason.
898 /// If this value is larger than the configured service limit it will be clamped to that limit.
899 ///
900 /// Default: `0` meters
901 pub fn radius(mut self, radius: i32) -> Self {
902 self.radius = Some(radius);
903 self
904 }
905
906 /// Whether or not to rank the edge candidates for this location.
907 ///
908 /// The ranking is used as a penalty within the routing algorithm so that some edges will be
909 /// penalized more heavily than others:
910 /// - If `true`, candidates will be ranked according to their distance from the input and
911 /// various other attributes.
912 /// - If `false` the candidates will all be treated as equal which should lead to routes that
913 /// are just the most optimal path with emphasis about which edges were selected.
914 pub fn rank_candidates(mut self, rank_candidates: bool) -> Self {
915 self.rank_candidates = Some(rank_candidates);
916 self
917 }
918 /// Which side of the road the location should be visited from.
919 ///
920 /// Whether the location should be visited from the [`Side::Same`], [`Side::Opposite`] or [`Side::Either`] side of
921 /// the road with respect to the side of the road the given locale drives on:
922 /// - In Germany (driving on the right side of the road), passing a value of same will only allow
923 /// you to leave from or arrive at a location such that the location will be on your right.
924 /// - In Australia (driving on the left side of the road), passing a value of same will force the location to be on
925 /// your left.
926 ///
927 /// A value of opposite will enforce arriving/departing from a location on the opposite side
928 /// of the road from that which you would be driving on while a value of either will make
929 /// no attempt limit the side of street that is available for the route.
930 ///
931 /// **Note:** If the location is not offset from the road centerline or is closest to an intersection
932 /// this option has no effect.
933 pub fn preferred_side(mut self, preferred_side: Side) -> Self {
934 self.preferred_side = Some(preferred_side);
935 self
936 }
937 /// Sets the type of the location
938 ///
939 /// Either [`LocationType::Break`], [`LocationType::Through`], [`LocationType::Via`] or [`LocationType::BreakThrough`].
940 /// The types of the first and last locations are ignored and are treated as [`LocationType::Break`].
941 /// Each type controls two characteristics:
942 /// - whether or not to allow an u-turn at the location and
943 /// - whether or not to generate guidance/legs at the location.
944 ///
945 /// Here is their behaviour:
946 /// - A [`LocationType::Break`] is a location at which we allows u-turns and generate legs and
947 /// arrival/departure maneuvers.
948 /// - A [`LocationType::Through`] location is a location at which we neither allow u-turns
949 /// nor generate legs or arrival/departure maneuvers.
950 /// - A [`LocationType::Via`] location is a location at which we allow u-turns,
951 /// but do not generate legs or arrival/departure maneuvers.
952 /// - A [`LocationType::BreakThrough`] location is a location at which we do not allow u-turns,
953 /// but do generate legs and arrival/departure maneuvers.
954 ///
955 /// Default: [`LocationType::Break`]
956 pub fn r#type(mut self, r#type: LocationType) -> Self {
957 self.r#type = Some(r#type);
958 self
959 }
960
961 /// Preferred direction of travel for the start from the location.
962 ///
963 /// This can be useful for mobile routing where a vehicle is traveling in a specific direction
964 /// along a road, and the route should start in that direction.
965 /// The heading is indicated in degrees from north in a clockwise direction:
966 /// - where north is `0°`,
967 /// - east is `90°`,
968 /// - south is `180°`, and
969 /// - west is `270°`.
970 pub fn heading(mut self, heading: u32) -> Self {
971 self.heading = Some(heading);
972 self
973 }
974 /// How close in degrees a given street's heading angle must be in order for it to be considered
975 /// as in the same direction of the heading parameter.
976 ///
977 /// The heading angle can be set via [`Self::heading`]
978 ///
979 /// Default: `60` degrees
980 pub fn heading_tolerance(mut self, heading_tolerance: u32) -> Self {
981 self.heading_tolerance = Some(heading_tolerance);
982 self
983 }
984 /// Location or business name.
985 ///
986 /// May be used in the route narration directions.
987 /// Example: `"You have arrived at <business name>"`
988 pub fn name(mut self, name: impl ToString) -> Self {
989 self.name = Some(name.to_string());
990 self
991 }
992 /// Cutoff at which we will assume the input is too far away from civilisation to be worth
993 /// correlating to the nearest graph elements.
994 ///
995 /// Default: `35 km`
996 pub fn search_cutoff(mut self, search_cutoff: f32) -> Self {
997 self.search_cutoff = Some(search_cutoff);
998 self
999 }
1000 /// During edge correlation this is the tolerance used to determine whether or not to snap to
1001 /// the intersection rather than along the street, if the snap location is within this distance
1002 /// from the intersection is used instead.
1003 ///
1004 /// Default: `5 meters`
1005 pub fn node_snap_tolerance(mut self, node_snap_tolerance: f32) -> Self {
1006 self.node_snap_tolerance = Some(node_snap_tolerance);
1007 self
1008 }
1009 /// Sets the tolerance for street side changes.
1010 ///
1011 /// The value means:
1012 /// - If your input coordinate is less than this tolerance away from the edge centerline then we
1013 /// set your side of street to none.
1014 /// - Otherwise your side of street will be left or right depending on direction of travel.
1015 ///
1016 /// Default: `5 meters`
1017 pub fn street_side_tolerance(mut self, street_side_tolerance: f32) -> Self {
1018 self.street_side_tolerance = Some(street_side_tolerance);
1019 self
1020 }
1021 /// The max distance in meters that the input coordinates or display ll can be from the edge
1022 /// centerline for them to be used for determining the side of street.
1023 ///
1024 /// Beyond this distance the side of street is set to none.
1025 ///
1026 /// Default: `1000 meters`
1027 pub fn street_side_max_distance(mut self, street_side_max_distance: f32) -> Self {
1028 self.street_side_max_distance = Some(street_side_max_distance);
1029 self
1030 }
1031
1032 /// Allows configuring the preferred side selection.
1033 ///
1034 /// Disables the preferred side (set via [`Self::preferred_side`]) when set to [`Side::Same`]
1035 /// or [`Side::Opposite`], if the edge has a road class less than that provided by this value.
1036 ///
1037 /// The road class must be one of the following strings:
1038 /// - `motorway`,
1039 /// - `trunk`,
1040 /// - `primary`,
1041 /// - `secondary`,
1042 /// - `tertiary`,
1043 /// - `unclassified`,
1044 /// - `residential` or
1045 /// - `service_other`.
1046 ///
1047 /// Default: `service_other` so that the preferred side will not be disabled for any edges
1048 pub fn street_side_cutoff(mut self, street_side_cutoff: f32) -> Self {
1049 self.street_side_cutoff = Some(street_side_cutoff);
1050 self
1051 }
1052 /// Expected date/time for the user to be at the location in the local time zone of departure or arrival.
1053 ///
1054 /// Offers more granularity over setting time than the global [`Manifest::date_time`].
1055 ///
1056 /// If waiting was set on this location in the request, and it's an intermediate location,
1057 /// the date_time will describe the departure time at this location.
1058 pub fn date_time(mut self, date_time: chrono::NaiveDateTime) -> Self {
1059 self.date_time = Some(date_time);
1060 self
1061 }
1062 /// The waiting time at this location.
1063 ///
1064 /// Only works if [`Manifest::r#type`] was set to
1065 /// - [`LocationType::Break`] or
1066 /// - [`LocationType::BreakThrough`]
1067 ///
1068 /// Example:
1069 /// A route describes a pizza delivery tour.
1070 /// Each location has a service time, which can be respected by setting waiting on the location.
1071 /// Then the departure will be delayed by this duration.
1072 pub fn waiting(mut self, waiting: chrono::Duration) -> Self {
1073 self.waiting = Some(waiting.num_seconds());
1074 self
1075 }
1076 /// A set of optional filters to exclude candidate edges based on their attribution.
1077 pub fn search_filter(mut self, search_filter: SearchFilter) -> Self {
1078 self.search_filter = Some(search_filter);
1079 self
1080 }
1081}
1082
1083#[serde_with::skip_serializing_none]
1084#[derive(Serialize, Deserialize, Default, Clone, Debug)]
1085/// A location is a point on the map that can be used to start or end a route.
1086pub struct Location {
1087 #[serde(rename = "lat")]
1088 latitude: f32,
1089 #[serde(rename = "lon")]
1090 longitude: f32,
1091 display_lat: Option<f32>,
1092 display_lon: Option<f32>,
1093 street: Option<String>,
1094 way_id: Option<i64>,
1095 minimum_reachability: Option<i32>,
1096 radius: Option<i32>,
1097 rank_candidates: Option<bool>,
1098 preferred_side: Option<Side>,
1099 #[serde(rename = "type")]
1100 r#type: Option<LocationType>,
1101 heading: Option<u32>,
1102 heading_tolerance: Option<u32>,
1103 name: Option<String>,
1104 search_cutoff: Option<f32>,
1105 node_snap_tolerance: Option<f32>,
1106 street_side_tolerance: Option<f32>,
1107 street_side_max_distance: Option<f32>,
1108 street_side_cutoff: Option<f32>,
1109 /// The waiting time in seconds at this location
1110 waiting: Option<i64>,
1111 /// Expected date/time for the user to be at the location.
1112 #[serde(serialize_with = "super::serialize_naive_date_time_opt")]
1113 date_time: Option<chrono::NaiveDateTime>,
1114 /// A set of optional filters to exclude candidate edges based on their attribution.
1115 search_filter: Option<SearchFilter>,
1116}
1117
1118/// A set of optional filters to exclude candidate edges based on their attribution.
1119#[serde_with::skip_serializing_none]
1120#[derive(Serialize, Deserialize, Default, Clone, Debug)]
1121pub struct SearchFilter {
1122 exclude_tunnel: Option<bool>,
1123 exclude_bridge: Option<bool>,
1124 exclude_toll: Option<bool>,
1125 exclude_ferry: Option<bool>,
1126 exclude_ramp: Option<bool>,
1127 exclude_closures: Option<bool>,
1128 min_road_class: Option<RoadClass>,
1129 max_road_class: Option<RoadClass>,
1130 level: Option<f32>,
1131}
1132impl SearchFilter {
1133 #[must_use]
1134 /// Creates a new instance of [`SearchFilter`].
1135 pub fn builder() -> Self {
1136 Default::default()
1137 }
1138
1139 /// Whether to exclude roads marked as tunnels
1140 ///
1141 /// Default: `false`
1142 pub fn exclude_tunnel(mut self, exclude_tunnel: bool) -> Self {
1143 self.exclude_tunnel = Some(exclude_tunnel);
1144 self
1145 }
1146 /// Whether to exclude roads marked as bridges
1147 ///
1148 /// Default: `false`
1149 pub fn exclude_bridge(mut self, exclude_bridge: bool) -> Self {
1150 self.exclude_bridge = Some(exclude_bridge);
1151 self
1152 }
1153 /// Whether to exclude toll
1154 ///
1155 /// Default: `false`
1156 pub fn exclude_toll(mut self, exclude_toll: bool) -> Self {
1157 self.exclude_toll = Some(exclude_toll);
1158 self
1159 }
1160 /// Whether to exclude ferry
1161 ///
1162 /// Default: `false`
1163 pub fn exclude_ferry(mut self, exclude_ferry: bool) -> Self {
1164 self.exclude_ferry = Some(exclude_ferry);
1165 self
1166 }
1167 /// Whether to exclude link roads marked as ramps, note that some turn channels are also marked as ramps
1168 ///
1169 /// Default: `false`
1170 pub fn exclude_ramp(mut self, exclude_ramp: bool) -> Self {
1171 self.exclude_ramp = Some(exclude_ramp);
1172 self
1173 }
1174 /// Whether to exclude roads considered closed due to live traffic closure.
1175 ///
1176 /// Note:
1177 /// - This option cannot be set if the costing option `ignore_closures` is also specified.
1178 /// - Ignoring closures at destination and source locations does NOT work for date_time type 0/1 & 2 respectively
1179 ///
1180 /// Default: `true`
1181 pub fn exclude_closures(mut self, exclude_closures: bool) -> Self {
1182 self.exclude_closures = Some(exclude_closures);
1183 self
1184 }
1185 /// Lowest road class allowed
1186 ///
1187 /// Default: [`RoadClass::ServiceOther`]
1188 pub fn min_road_class(mut self, min_road_class: RoadClass) -> Self {
1189 self.min_road_class = Some(min_road_class);
1190 self
1191 }
1192 /// Highest road class allowed
1193 ///
1194 /// Default: [`RoadClass::Motorway`]
1195 pub fn max_road_class(mut self, max_road_class: RoadClass) -> Self {
1196 self.max_road_class = Some(max_road_class);
1197 self
1198 }
1199 /// BETA Will only consider edges that are on or traverse the passed floor level.
1200 ///
1201 /// Sets `search_cutoff` to a default value of 300 meters if no cutoff value is passed.
1202 /// Additionally, if a `search_cutoff` is passed, it will be clamped to 1000 meters.
1203 pub fn level(mut self, level: f32) -> Self {
1204 self.level = Some(level);
1205 self
1206 }
1207}
1208
1209/// Road classes from highest to lowest
1210#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1211#[repr(u8)]
1212pub enum RoadClass {
1213 /// equivalent to OSMs [`highway=motorway`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dmotorway)
1214 #[serde(rename = "motorway")]
1215 Motorway = 8,
1216 /// equivalent to OSMs [`highway=trunk`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dtrunk)
1217 #[serde(rename = "trunk")]
1218 Trunk = 6,
1219 /// equivalent to OSMs [`highway=primary`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dprimary)
1220 #[serde(rename = "primary")]
1221 Primary = 5,
1222 /// equivalent to OSMs [`highway=secondary`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dsecondary)
1223 #[serde(rename = "secondary")]
1224 Secondary = 4,
1225 /// equivalent to OSMs [`highway=tertiary`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dtertiary)
1226 #[serde(rename = "tertiary")]
1227 Tertiary = 3,
1228 /// equivalent to OSMs [`highway=unclassified`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dunclassified)
1229 #[serde(rename = "unclassified")]
1230 Unclassified = 2,
1231 /// equivalent to OSMs [`highway=residential`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dresidential)
1232 #[serde(rename = "residential")]
1233 Residential = 1,
1234 /// equivalent to OSMs [`highway=service`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dservice) or
1235 /// or [`highway=other`](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dother)
1236 #[serde(rename = "service_other")]
1237 ServiceOther = 0,
1238}
1239
1240#[cfg(test)]
1241mod test {
1242 use super::*;
1243 #[test]
1244 fn serialisation() {
1245 assert_eq!(
1246 serde_json::to_value(Manifest::default()).unwrap(),
1247 serde_json::json!({"locations": []})
1248 );
1249 }
1250}