paiagram/rw_data/
gtfs.rs

1use std::{collections::HashMap, io::Cursor};
2
3use bevy::prelude::*;
4use egui::Pos2;
5use moonshine_core::kind::{InsertInstance, Instance};
6
7use crate::{
8    graph::{Graph, Station},
9    units::time::TimetableTime,
10    vehicles::{
11        Vehicle,
12        entries::{TimetableEntry, TravelMode, VehicleSchedule},
13        vehicle_set::VehicleSet,
14    },
15};
16
17#[derive(Event, Deref)]
18pub struct GtfsLoaded(pub Vec<u8>);
19
20pub fn load_gtfs_static(data: On<GtfsLoaded>, mut commands: Commands, mut graph: ResMut<Graph>) {
21    let reader = Cursor::new(data.as_slice());
22    let Ok(gtfs) = gtfs_structures::Gtfs::from_reader(reader) else {
23        return;
24    };
25    let mut station_map: HashMap<String, Instance<Station>> =
26        HashMap::with_capacity(gtfs.stops.len());
27    for (_, stop) in gtfs.stops.iter() {
28        let longitude = stop.longitude.unwrap_or_default();
29        let latitude = stop.latitude.unwrap_or_default();
30        let name = stop.name.as_ref().unwrap_or(&stop.id);
31        let (northing, easting, _) = utm::to_utm_wgs84_no_zone(latitude, longitude);
32        let station_instance = commands
33            .spawn((Name::new(name.clone()),))
34            .insert_instance(Station(Pos2 {
35                x: easting as f32,
36                y: -northing as f32,
37            }))
38            .instance();
39        graph.add_node(station_instance);
40        station_map.insert(stop.id.clone(), station_instance);
41    }
42    let vehicle_set_entity = commands
43        .spawn((Name::new("New GTFS Import"), VehicleSet))
44        .id();
45    for (_, trip) in gtfs.trips.into_iter() {
46        let vehicle_entity = commands
47            .spawn(Name::new(trip.route_id))
48            .insert_instance(Vehicle)
49            .id();
50        commands
51            .entity(vehicle_set_entity)
52            .add_child(vehicle_entity);
53        let mut schedule_entities = Vec::new();
54        for stop_time in trip.stop_times {
55            let arrival = stop_time.arrival_time.map_or(TravelMode::Flexible, |t| {
56                TravelMode::At(TimetableTime(t as i32))
57            });
58            let departure = Some(stop_time.departure_time.map_or(TravelMode::Flexible, |t| {
59                TravelMode::At(TimetableTime(t as i32))
60            }));
61            let Some(station_instance) = station_map.get(&stop_time.stop.id) else {
62                continue;
63            };
64            let entry_entity = commands
65                .spawn(TimetableEntry {
66                    station: station_instance.entity(),
67                    arrival,
68                    departure,
69                    service: None,
70                    track: None,
71                })
72                .id();
73            commands.entity(vehicle_entity).add_child(entry_entity);
74            schedule_entities.push(entry_entity);
75        }
76        commands.entity(vehicle_entity).insert(VehicleSchedule {
77            entities: schedule_entities,
78            ..Default::default()
79        });
80    }
81}