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}