@@ -241,6 +241,26 @@ class StopTime(Entity):
241241 def stop (self ):
242242 return self ._gtfs .stops [self .stop_id ]
243243
244+ class ItineraryCell (Entity ):
245+ _schema = File (id = 'itinerary_index' ,
246+ name = 'itinerary_cells' ,
247+ fileType = FileType .CSV ,
248+ required = True ,
249+ group_id = 'stop_sequence' )
250+
251+ stop_id : str
252+ stop_sequence : int
253+ pickup_type : PickupType = PickupType .REGULARLY_SCHEDULED
254+ drop_off_type : DropOffType = DropOffType .REGULARLY_SCHEDULED
255+ mean_duration_factor : Optional [float ] = None
256+ mean_duration_offset : Optional [float ] = None
257+ safe_duration_factor : Optional [float ] = None
258+ safe_duration_offset : Optional [float ] = None
259+
260+ @property
261+ def stop (self ):
262+ return self ._gtfs .stops [self .stop_id ]
263+
244264
245265class Transfer (Entity ):
246266 _schema = File (id = 'from_trip_id' ,
@@ -325,16 +345,85 @@ def last_stop(self):
325345 @cached_property
326346 def route (self ):
327347 return self ._gtfs .routes [self .route_id ]
348+
349+ class ItineraryTrip (Entity ):
350+ _schema = File (id = 'trip_id' ,
351+ fileType = FileType .CSV ,
352+ name = 'trips' ,
353+ required = True )
354+
355+ trip_id : str
356+ service_id : str
357+ block_id : str = ''
358+ route_id : str
359+ itinerary_index : str
360+ departure_times : List [int ]
361+ arrival_times : List [int ]
362+ start_pickup_drop_off_windows : List [int ]
363+ end_pickup_drop_off_windows : List [int ]
364+
365+ @property
366+ def first_itinerary_cell (self ):
367+ return self ._gtfs .itinerary_cells [self .itinerary_index ][0 ]
368+
369+ @property
370+ def last_itinerary_cell (self ):
371+ return self ._gtfs .itinerary_cells [self .itinerary_index ][- 1 ]
372+
373+ @property
374+ def stop_shape (self ):
375+ locations = tuple (self ._gtfs .stops [st .stop_id ].location for st in self ._gtfs .itinerary_cells [self .itinerary_index ])
376+
377+ if None in locations :
378+ return None
379+ return locations
380+
381+ @cached_property
382+ def shift_days (self ):
383+ return 1 if self .departure_times [0 ] >= DAY_SEC else 0
384+
385+ @cached_property
386+ def first_departure (self ):
387+ return self .departure_times [0 ] - DAY_SEC * self .shift_days
388+
389+ @cached_property
390+ def last_arrival (self ):
391+ return self .arrival_times [- 1 ] - DAY_SEC * self .shift_days
392+
393+ @cached_property
394+ def first_point (self ):
395+ return self .first_stop .location
396+
397+ @cached_property
398+ def last_point (self ):
399+ return self .last_stop .location
400+
401+ @cached_property
402+ def first_stop (self ):
403+ return self ._gtfs .stops [self .first_itinerary_cell .stop_id ]
404+
405+ @cached_property
406+ def last_stop (self ):
407+ return self ._gtfs .stops [self .last_itinerary_cell .stop_id ]
408+
409+ @cached_property
410+ def route (self ):
411+ return self ._gtfs .routes [self .route_id ]
328412
329413
330414GTFS_SUBSET_SCHEMA = FileCollection (Agency , BookingRule , Calendar , CalendarDate ,
331415 Locations , LocationGroups , Routes , Transfer , Trip , Stop , StopTime )
332416
417+ GTFS_SUBSET_SCHEMA_ITINERARIES = FileCollection (Agency , BookingRule , Calendar , CalendarDate , ItineraryCell ,
418+ ItineraryTrip , Locations , LocationGroups , Routes , Transfer , Stop )
419+
333420GTFS_FILENAMES = {
334421 Agency ._schema .name : Agency ,
335422 BookingRule ._schema .name : BookingRule ,
336423 Calendar ._schema .name : Calendar ,
337424 CalendarDate ._schema .name : CalendarDate ,
425+ ItineraryCell ._schema .name : ItineraryCell ,
426+ ItineraryTrip ._schema .name : ItineraryTrip ,
338427 Locations ._schema .name : Locations ,
339428 LocationGroups ._schema .name : LocationGroups ,
340429 Routes ._schema .name : Routes ,
0 commit comments