Skip to content

Commit

Permalink
Store and plumb back route info
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed May 25, 2024
1 parent f9e086c commit 1070932
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 9 deletions.
26 changes: 26 additions & 0 deletions backend/src/gtfs/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub mod orig_ids {

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ServiceID(String);

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct RouteID(String);
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
Expand All @@ -23,6 +26,9 @@ pub struct StopID(pub usize);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TripID(pub usize);

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct RouteID(pub usize);

impl CheapID for StopID {
fn new(x: usize) -> Self {
Self(x)
Expand All @@ -33,6 +39,11 @@ impl CheapID for TripID {
Self(x)
}
}
impl CheapID for RouteID {
fn new(x: usize) -> Self {
Self(x)
}
}

pub trait CheapID: Copy {
fn new(x: usize) -> Self;
Expand All @@ -59,7 +70,22 @@ impl<K: Clone + std::fmt::Debug + Ord, V: CheapID> IDMapping<K, V> {
Ok(cheap)
}

pub fn insert_idempotent(&mut self, orig: &K) -> V {
match self.orig_to_cheap.get(orig) {
Some(x) => *x,
None => {
let v = V::new(self.orig_to_cheap.len());
self.orig_to_cheap.insert(orig.clone(), v);
v
}
}
}

pub fn get(&self, orig: &K) -> Option<V> {
self.orig_to_cheap.get(orig).cloned()
}

pub fn borrow(&self) -> &BTreeMap<K, V> {
&self.orig_to_cheap
}
}
24 changes: 23 additions & 1 deletion backend/src/gtfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use utils::Mercator;

use self::ids::orig_ids;
pub use self::ids::{StopID, TripID};
pub use self::ids::{RouteID, StopID, TripID};
use crate::graph::RoadID;

mod ids;
Expand All @@ -20,6 +20,7 @@ pub struct GtfsModel {
// Indexed by StopID and TripID
pub stops: Vec<Stop>,
pub trips: Vec<Trip>,
pub routes: Vec<Route>,
}

#[derive(Serialize, Deserialize)]
Expand All @@ -45,13 +46,23 @@ pub struct NextStep {
pub struct Trip {
// (stop, arrival time) in order
pub stop_sequence: Vec<(StopID, NaiveTime)>,
pub route: RouteID,
}

#[derive(Serialize, Deserialize)]
pub struct Route {
pub orig_id: orig_ids::RouteID,
pub short_name: Option<String>,
pub long_name: Option<String>,
pub description: Option<String>,
}

impl GtfsModel {
pub fn empty() -> Self {
Self {
stops: Vec::new(),
trips: Vec::new(),
routes: Vec::new(),
}
}

Expand Down Expand Up @@ -85,3 +96,14 @@ impl Stop {
f
}
}

impl Route {
pub fn describe(&self) -> String {
self.description
.as_ref()
.or(self.long_name.as_ref())
.or(self.short_name.as_ref())
.map(|x| x.to_string())
.unwrap_or_else(|| format!("{:?}", self.orig_id))
}
}
52 changes: 47 additions & 5 deletions backend/src/gtfs/scrape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::Deserialize;
use utils::Mercator;

use super::ids::{orig_ids, IDMapping};
use super::{GtfsModel, NextStep, Stop, StopID, Trip, TripID};
use super::{GtfsModel, NextStep, Route, RouteID, Stop, StopID, Trip, TripID};
use crate::graph::RoadID;

// Move to mod after deciding to store every day
Expand All @@ -28,11 +28,13 @@ impl GtfsModel {
pub fn parse(dir_path: &str, mercator: &Mercator) -> Result<GtfsModel> {
info!("Scraping trips.txt");
let mut trip_to_service: BTreeMap<orig_ids::TripID, orig_ids::ServiceID> = BTreeMap::new();
let mut trip_to_route: BTreeMap<orig_ids::TripID, orig_ids::RouteID> = BTreeMap::new();
for rec in
csv::Reader::from_reader(File::open(format!("{dir_path}/trips.txt"))?).deserialize()
{
let rec: TripRow = rec?;
trip_to_service.insert(rec.trip_id, rec.service_id);
trip_to_service.insert(rec.trip_id.clone(), rec.service_id);
trip_to_route.insert(rec.trip_id, rec.route_id);
}

info!("Scraping calendar.txt");
Expand All @@ -58,6 +60,23 @@ impl GtfsModel {
service_to_days.insert(rec.service_id, days);
}

info!("Scraping routes.txt");
let mut routes_table: BTreeMap<orig_ids::RouteID, Route> = BTreeMap::new();
for rec in
csv::Reader::from_reader(File::open(format!("{dir_path}/routes.txt"))?).deserialize()
{
let rec: RouteRow = rec?;
routes_table.insert(
rec.route_id.clone(),
Route {
orig_id: rec.route_id,
short_name: rec.route_short_name,
long_name: rec.route_long_name,
description: rec.route_desc,
},
);
}

info!("Scraping stops.txt");
let mut stop_ids: IDMapping<orig_ids::StopID, StopID> = IDMapping::new();
let mut stops: Vec<Stop> = Vec::new();
Expand Down Expand Up @@ -85,6 +104,7 @@ impl GtfsModel {

info!("Scraping stop_times.txt");
let mut trips_table: BTreeMap<orig_ids::TripID, Trip> = BTreeMap::new();
let mut route_ids: IDMapping<orig_ids::RouteID, RouteID> = IDMapping::new();
for rec in csv::Reader::from_reader(File::open(format!("{dir_path}/stop_times.txt"))?)
.deserialize()
{
Expand Down Expand Up @@ -112,17 +132,26 @@ impl GtfsModel {
}

trips_table
.entry(rec.trip_id)
.entry(rec.trip_id.clone())
.or_insert_with(|| Trip {
stop_sequence: Vec::new(),
route: route_ids.insert_idempotent(&trip_to_route[&rec.trip_id]),
})
.stop_sequence
.push((stop_id, arrival_time));
}

// Produce a compact Trips vec
// Produce compact vectors of used things
let trips: Vec<Trip> = trips_table.into_values().collect();

let mut routes: Vec<Route> = route_ids
.borrow()
.keys()
.map(|orig_id| routes_table.remove(orig_id).unwrap())
.collect();
// TODO Sorting is a bit silly; we could fill this out directly in order
routes.sort_by_key(|r| route_ids.get(&r.orig_id));

// Precompute the next steps from each stop
for (idx, trip) in trips.iter().enumerate() {
let trip_id = TripID(idx);
Expand All @@ -142,14 +171,19 @@ impl GtfsModel {
stop.next_steps.sort_by_key(|x| x.time1);
}

Ok(GtfsModel { stops, trips })
Ok(GtfsModel {
stops,
trips,
routes,
})
}
}

#[derive(Deserialize)]
struct TripRow {
trip_id: orig_ids::TripID,
service_id: orig_ids::ServiceID,
route_id: orig_ids::RouteID,
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -178,3 +212,11 @@ struct StopTimeRow {
stop_id: orig_ids::StopID,
arrival_time: String,
}

#[derive(Deserialize)]
struct RouteRow {
route_id: orig_ids::RouteID,
route_short_name: Option<String>,
route_long_name: Option<String>,
route_desc: Option<String>,
}
6 changes: 4 additions & 2 deletions backend/src/transit_route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,11 @@ fn render_path(

if let Some(trip) = trip_id {
f.set_property("kind", "transit");
// TODO Plumb a route name or something
// TODO Plumb points showing stop times? maybe for both cases
f.set_property("trip", trip.0);
f.set_property(
"route",
graph.gtfs.routes[graph.gtfs.trips[trip.0].route.0].describe(),
);
f.set_property("num_stops", num_stops);
} else {
f.set_property("kind", "road");
Expand Down
2 changes: 1 addition & 1 deletion web/src/RouteMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<li>Walk</li>
{:else}
<li>
Take transit (trip {props.trip}) for {props.num_stops} stops
Take {props.route} for {props.num_stops} stops
</li>
{/if}
{/each}
Expand Down

0 comments on commit 1070932

Please sign in to comment.