hrdf_routing_engine/routing/
models.rs

1use chrono::{Duration, NaiveDateTime};
2use hrdf_parser::{Coordinates, DataStorage, Journey};
3use rustc_hash::FxHashSet;
4use serde::Serialize;
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct RouteSection {
8    journey_id: Option<i32>,
9    departure_stop_id: i32,
10    arrival_stop_id: i32,
11    arrival_at: NaiveDateTime,
12    duration: Option<i16>,
13}
14
15impl RouteSection {
16    pub fn new(
17        journey_id: Option<i32>,
18        departure_stop_id: i32,
19        arrival_stop_id: i32,
20        arrival_at: NaiveDateTime,
21        duration: Option<i16>,
22    ) -> Self {
23        Self {
24            journey_id,
25            departure_stop_id,
26            arrival_stop_id,
27            arrival_at,
28            duration,
29        }
30    }
31
32    // Getters/Setters
33
34    pub fn journey_id(&self) -> Option<i32> {
35        self.journey_id
36    }
37
38    pub fn departure_stop_id(&self) -> i32 {
39        self.departure_stop_id
40    }
41
42    pub fn arrival_stop_id(&self) -> i32 {
43        self.arrival_stop_id
44    }
45
46    pub fn set_arrival_stop_id(&mut self, value: i32) {
47        self.arrival_stop_id = value;
48    }
49
50    pub fn arrival_at(&self) -> NaiveDateTime {
51        self.arrival_at
52    }
53
54    pub fn set_arrival_at(&mut self, value: NaiveDateTime) {
55        self.arrival_at = value;
56    }
57
58    pub fn duration(&self) -> Option<i16> {
59        self.duration
60    }
61
62    // Functions
63
64    // pub fn journey<'a>(&'a self, data_storage: &'a DataStorage) -> Option<&Journey> {
65    //     self.journey_id.map(|id| data_storage.journeys().find(id))?
66    pub fn journey<'a>(&'a self, data_storage: &'a DataStorage) -> Option<&'a Journey> {
67        self.journey_id.map(|id| {
68            data_storage
69                .journeys()
70                .find(id)
71                .unwrap_or_else(|| panic!("Journey {:?} not found.", id))
72        })
73    }
74}
75
76#[derive(Debug, Clone, PartialEq)]
77pub struct Route {
78    sections: Vec<RouteSection>,
79    visited_stops: FxHashSet<i32>,
80}
81
82impl Route {
83    pub fn new(sections: Vec<RouteSection>, visited_stops: FxHashSet<i32>) -> Self {
84        Self {
85            sections,
86            visited_stops,
87        }
88    }
89
90    // Getters/Setters
91
92    pub fn sections(&self) -> &Vec<RouteSection> {
93        &self.sections
94    }
95
96    pub fn visited_stops(&self) -> &FxHashSet<i32> {
97        &self.visited_stops
98    }
99
100    // Functions
101
102    pub fn last_section(&self) -> &RouteSection {
103        // A route always contains at least one section.
104        self.sections.last().unwrap()
105    }
106
107    pub fn last_section_mut(&mut self) -> &mut RouteSection {
108        // A route always contains at least one section.
109        self.sections.last_mut().unwrap()
110    }
111
112    pub fn arrival_stop_id(&self) -> i32 {
113        self.last_section().arrival_stop_id()
114    }
115
116    pub fn arrival_at(&self) -> NaiveDateTime {
117        self.last_section().arrival_at()
118    }
119
120    pub fn has_visited_any_stops(&self, stops: &FxHashSet<i32>) -> bool {
121        !self.visited_stops.is_disjoint(stops)
122    }
123
124    pub fn sections_having_journey(&self) -> Vec<&RouteSection> {
125        self.sections
126            .iter()
127            .filter(|section| section.journey_id().is_some())
128            .collect()
129    }
130
131    pub fn count_connections(&self) -> usize {
132        self.sections_having_journey().len()
133    }
134}
135
136#[derive(Copy, Clone, Eq, PartialEq)]
137pub enum RoutingAlgorithmMode {
138    SolveFromDepartureStopToArrivalStop,
139    SolveFromDepartureStopToReachableArrivalStops,
140}
141
142pub struct RoutingAlgorithmArgs {
143    mode: RoutingAlgorithmMode,
144    arrival_stop_id: Option<i32>,
145    time_limit: Option<NaiveDateTime>,
146}
147
148impl RoutingAlgorithmArgs {
149    pub fn new(
150        mode: RoutingAlgorithmMode,
151        arrival_stop_id: Option<i32>,
152        time_limit: Option<NaiveDateTime>,
153    ) -> Self {
154        Self {
155            mode,
156            arrival_stop_id,
157            time_limit,
158        }
159    }
160
161    pub fn solve_from_departure_stop_to_arrival_stop(arrival_stop_id: i32) -> Self {
162        Self::new(
163            RoutingAlgorithmMode::SolveFromDepartureStopToArrivalStop,
164            Some(arrival_stop_id),
165            None,
166        )
167    }
168
169    pub fn solve_from_departure_stop_to_reachable_arrival_stops(time_limit: NaiveDateTime) -> Self {
170        Self::new(
171            RoutingAlgorithmMode::SolveFromDepartureStopToReachableArrivalStops,
172            None,
173            Some(time_limit),
174        )
175    }
176
177    // Getters/Setters
178
179    pub fn mode(&self) -> RoutingAlgorithmMode {
180        self.mode
181    }
182
183    /// Do not call this function if you are not sure that arrival_stop_id is not None.
184    pub fn arrival_stop_id(&self) -> i32 {
185        self.arrival_stop_id.unwrap()
186    }
187
188    /// Do not call this function if you are not sure that time_limit is not None.
189    pub fn time_limit(&self) -> NaiveDateTime {
190        self.time_limit.unwrap()
191    }
192}
193
194#[derive(Debug, Clone, Serialize)]
195pub struct RouteResult {
196    departure_at: NaiveDateTime,
197    arrival_at: NaiveDateTime,
198    sections: Vec<RouteSectionResult>,
199}
200
201// impl Clone for RouteResult {
202//     fn clone(&self) -> Self {
203//         RouteResult {
204//             departure_at: self.departure_at,
205//             arrival_at: self.arrival_at,
206//             sections: self.sections.clone(),
207//         }
208//     }
209// }
210
211impl RouteResult {
212    pub fn new(
213        departure_at: NaiveDateTime,
214        arrival_at: NaiveDateTime,
215        sections: Vec<RouteSectionResult>,
216    ) -> Self {
217        Self {
218            departure_at,
219            arrival_at,
220            sections,
221        }
222    }
223
224    // Getters/Setters
225
226    pub fn departure_at(&self) -> NaiveDateTime {
227        self.departure_at
228    }
229
230    pub fn arrival_at(&self) -> NaiveDateTime {
231        self.arrival_at
232    }
233
234    pub fn sections(&self) -> &Vec<RouteSectionResult> {
235        &self.sections
236    }
237
238    pub fn number_changes(&self) -> usize {
239        if !self.sections().is_empty() {
240            self.sections()
241                .iter()
242                .filter(|s| !s.is_walking_trip())
243                .count()
244                - 1
245        } else {
246            0
247        }
248    }
249
250    pub fn total_walking_time(&self) -> Duration {
251        self.sections()
252            .iter()
253            .filter(|s| s.is_walking_trip())
254            .fold(Duration::minutes(0), |total, d| {
255                total + Duration::minutes(d.duration().unwrap_or(0i16) as i64)
256            })
257    }
258
259    pub fn total_time(&self) -> Duration {
260        self.arrival_at - self.departure_at
261    }
262
263    pub fn departure_stop_id(&self) -> Option<i32> {
264        self.sections().first().map(|s| s.departure_stop_id)
265    }
266
267    pub fn arrival_stop_id(&self) -> Option<i32> {
268        self.sections().last().map(|s| s.arrival_stop_id())
269    }
270
271    pub fn departure_stop_name(&self, data_storage: &DataStorage) -> Option<String> {
272        self.departure_stop_id().map(|id| {
273            String::from(
274                data_storage
275                    .stops()
276                    .find(id)
277                    .unwrap_or_else(|| panic!("stop {id} not found"))
278                    .name(),
279            )
280        })
281    }
282
283    pub fn arrival_stop_name(&self, data_storage: &DataStorage) -> Option<String> {
284        self.arrival_stop_id().map(|id| {
285            String::from(
286                data_storage
287                    .stops()
288                    .find(id)
289                    .unwrap_or_else(|| panic!("stop {id} not found"))
290                    .name(),
291            )
292        })
293    }
294}
295
296#[derive(Debug, Serialize, Copy, Clone)]
297pub struct RouteSectionResult {
298    journey_id: Option<i32>,
299    departure_stop_id: i32,
300    departure_stop_lv95_coordinates: Option<Coordinates>,
301    departure_stop_wgs84_coordinates: Option<Coordinates>,
302    arrival_stop_id: i32,
303    arrival_stop_lv95_coordinates: Option<Coordinates>,
304    arrival_stop_wgs84_coordinates: Option<Coordinates>,
305    departure_at: Option<NaiveDateTime>,
306    arrival_at: Option<NaiveDateTime>,
307    duration: Option<i16>,
308}
309
310impl RouteSectionResult {
311    #[allow(clippy::too_many_arguments)]
312    pub fn new(
313        journey_id: Option<i32>,
314        departure_stop_id: i32,
315        departure_stop_lv95_coordinates: Option<Coordinates>,
316        departure_stop_wgs84_coordinates: Option<Coordinates>,
317        arrival_stop_id: i32,
318        arrival_stop_lv95_coordinates: Option<Coordinates>,
319        arrival_stop_wgs84_coordinates: Option<Coordinates>,
320        departure_at: Option<NaiveDateTime>,
321        arrival_at: Option<NaiveDateTime>,
322        duration: Option<i16>,
323    ) -> Self {
324        Self {
325            journey_id,
326            departure_stop_id,
327            departure_stop_lv95_coordinates,
328            departure_stop_wgs84_coordinates,
329            arrival_stop_id,
330            arrival_stop_lv95_coordinates,
331            arrival_stop_wgs84_coordinates,
332            departure_at,
333            arrival_at,
334            duration,
335        }
336    }
337
338    // Getters/Setters
339
340    pub fn departure_stop_id(&self) -> i32 {
341        self.departure_stop_id
342    }
343
344    pub fn departure_at(&self) -> Option<NaiveDateTime> {
345        self.departure_at
346    }
347
348    pub fn arrival_stop_id(&self) -> i32 {
349        self.arrival_stop_id
350    }
351
352    pub fn arrival_stop_lv95_coordinates(&self) -> Option<Coordinates> {
353        self.arrival_stop_lv95_coordinates
354    }
355
356    // pub fn arrival_stop_wgs84_coordinates(&self) -> Option<Coordinates> {
357    //     self.arrival_stop_wgs84_coordinates
358    // }
359
360    pub fn arrival_at(&self) -> Option<NaiveDateTime> {
361        self.arrival_at
362    }
363
364    pub fn duration(&self) -> Option<i16> {
365        self.duration
366    }
367
368    // Functions
369
370    // pub fn journey<'a>(&'a self, data_storage: &'a DataStorage) -> Option<&Journey> {
371    //     self.journey_id.map(|id| data_storage.journeys().find(id))?
372    pub fn journey<'a>(&'a self, data_storage: &'a DataStorage) -> Option<&'a Journey> {
373        self.journey_id.map(|id| {
374            data_storage
375                .journeys()
376                .find(id)
377                .unwrap_or_else(|| panic!("Journey {:?} not found.", id))
378        })
379    }
380
381    pub fn is_walking_trip(&self) -> bool {
382        self.journey_id.is_none()
383    }
384}