hrdf_routing_engine/routing/
models.rs1use 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 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 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 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 pub fn last_section(&self) -> &RouteSection {
103 self.sections.last().unwrap()
105 }
106
107 pub fn last_section_mut(&mut self) -> &mut RouteSection {
108 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 pub fn mode(&self) -> RoutingAlgorithmMode {
180 self.mode
181 }
182
183 pub fn arrival_stop_id(&self) -> i32 {
185 self.arrival_stop_id.unwrap()
186 }
187
188 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
201impl 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 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 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_at(&self) -> Option<NaiveDateTime> {
361 self.arrival_at
362 }
363
364 pub fn duration(&self) -> Option<i16> {
365 self.duration
366 }
367
368 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}