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