valhalla_client/
route.rs

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