@@ -4,7 +4,7 @@ use actix_web::web::Json;
4
4
use actix_web:: web:: Path ;
5
5
use actix_web:: web:: Query ;
6
6
use chrono:: Utc ;
7
- use chrono:: { DateTime , NaiveDateTime , TimeZone } ;
7
+ use chrono:: { DateTime , Duration , NaiveDateTime , TimeZone } ;
8
8
use editoast_derive:: EditoastError ;
9
9
use editoast_schemas:: train_schedule:: MarginValue ;
10
10
use editoast_schemas:: train_schedule:: PathItemLocation ;
@@ -70,7 +70,8 @@ enum STDCMError {
70
70
/// An STDCM request
71
71
#[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , ToSchema ) ]
72
72
pub struct STDCMRequestPayload {
73
- start_time : DateTime < Utc > ,
73
+ /// Deprecated, first step arrival time should be used instead
74
+ start_time : Option < DateTime < Utc > > ,
74
75
steps : Vec < PathfindingItem > ,
75
76
rolling_stock_id : i64 ,
76
77
comfort : Comfort ,
@@ -106,6 +107,12 @@ struct PathfindingItem {
106
107
duration : Option < u64 > ,
107
108
/// The associated location
108
109
location : PathItemLocation ,
110
+ /// Time at which the train should arrive at the location, if specified
111
+ arrival_time : Option < DateTime < Utc > > ,
112
+ /// The train may arrive up to this duration before the expected arrival time
113
+ arrival_time_tolerance_before : Option < u64 > ,
114
+ /// The train may arrive up to this duration after the expected arrival time
115
+ arrival_time_tolerance_after : Option < u64 > ,
109
116
}
110
117
111
118
const TWO_HOURS_IN_MILLISECONDS : u64 = 2 * 60 * 60 * 60 ;
@@ -209,6 +216,8 @@ async fn stdcm(
209
216
}
210
217
} ;
211
218
219
+ let departure_time = get_earliest_departure_time ( & data, maximum_run_time) ;
220
+
212
221
// 3. Parse stdcm path items
213
222
let path_items = parse_stdcm_steps ( conn, & data, & infra) . await ?;
214
223
@@ -223,7 +232,7 @@ async fn stdcm(
223
232
. clone ( ) ,
224
233
comfort : data. comfort ,
225
234
path_items,
226
- start_time : data . start_time ,
235
+ start_time : departure_time ,
227
236
trains_requirements,
228
237
maximum_departure_delay : Some ( data. maximum_departure_delay ) ,
229
238
maximum_run_time,
@@ -234,7 +243,7 @@ async fn stdcm(
234
243
time_step : Some ( 2000 ) ,
235
244
work_schedules : build_work_schedules (
236
245
conn,
237
- data . start_time ,
246
+ departure_time ,
238
247
data. maximum_departure_delay ,
239
248
maximum_run_time,
240
249
)
@@ -246,6 +255,34 @@ async fn stdcm(
246
255
Ok ( Json ( stdcm_response) )
247
256
}
248
257
258
+ /// Returns the earliest time at which the train may start
259
+ fn get_earliest_departure_time ( data : & STDCMRequestPayload , maximum_run_time : u64 ) -> DateTime < Utc > {
260
+ // Prioritize: start time, or first step time, or (first specified time - max run time)
261
+ data. start_time . unwrap_or (
262
+ data. steps
263
+ . first ( )
264
+ . and_then ( |step| step. arrival_time )
265
+ . unwrap_or (
266
+ get_earliest_step_time ( data) - Duration :: milliseconds ( maximum_run_time as i64 ) ,
267
+ ) ,
268
+ )
269
+ }
270
+
271
+ /// Returns the earliest time that has been set on any step
272
+ fn get_earliest_step_time ( data : & STDCMRequestPayload ) -> DateTime < Utc > {
273
+ // Get the earliest time that has been specified for any step
274
+ * data
275
+ . start_time
276
+ . as_ref ( )
277
+ . or_else ( || {
278
+ data. steps
279
+ . iter ( )
280
+ . flat_map ( |step| step. arrival_time . iter ( ) )
281
+ . next ( )
282
+ } )
283
+ . expect ( "No time specified for stdcm request" )
284
+ }
285
+
249
286
/// get the maximum run time, compute it if unspecified.
250
287
/// returns an enum with either the result or a SimulationResponse if it failed
251
288
async fn get_maximum_run_time (
@@ -263,13 +300,16 @@ async fn get_maximum_run_time(
263
300
} ) ;
264
301
}
265
302
303
+ // Doesn't matter for now, but eventually it will affect tmp speed limits
304
+ let approx_start_time = get_earliest_step_time ( data) ;
305
+
266
306
let train_schedule = TrainSchedule {
267
307
id : 0 ,
268
308
train_name : "" . to_string ( ) ,
269
309
labels : vec ! [ ] ,
270
310
rolling_stock_name : rolling_stock. name . clone ( ) ,
271
311
timetable_id,
272
- start_time : data . start_time ,
312
+ start_time : approx_start_time ,
273
313
schedule : vec ! [ ] ,
274
314
margins : build_single_margin ( data. margin ) ,
275
315
initial_speed : 0.0 ,
@@ -372,21 +412,22 @@ async fn parse_stdcm_steps(
372
412
) -> Result < Vec < STDCMPathItem > > {
373
413
let path_items = data. steps . clone ( ) ;
374
414
let mut locations = Vec :: with_capacity ( path_items. len ( ) ) ;
375
- let mut durations = Vec :: with_capacity ( path_items. len ( ) ) ;
376
415
for item in path_items {
377
416
locations. push ( item. location ) ;
378
- durations. push ( item. duration ) ;
379
417
}
380
418
381
419
let track_offsets = extract_location_from_path_items ( conn, infra. id , & locations) . await ?;
382
420
let track_offsets = track_offsets. map_err :: < STDCMError , _ > ( |err| err. into ( ) ) ?;
383
421
384
422
Ok ( track_offsets
385
423
. iter ( )
386
- . zip ( durations )
387
- . map ( |( track_offset, duration ) | STDCMPathItem {
388
- stop_duration : duration,
424
+ . zip ( & data . steps )
425
+ . map ( |( track_offset, path_item ) | STDCMPathItem {
426
+ stop_duration : path_item . duration ,
389
427
locations : track_offset. to_vec ( ) ,
428
+ arrival_time : path_item. arrival_time ,
429
+ arrival_time_tolerance_before : path_item. arrival_time_tolerance_before ,
430
+ arrival_time_tolerance_after : path_item. arrival_time_tolerance_after ,
390
431
} )
391
432
. collect ( ) )
392
433
}
0 commit comments