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