WIP load gtfs

This commit is contained in:
Dustin Carlino 2018-09-06 13:43:00 -07:00
parent c5c00d5740
commit 1d732c5a3b
9 changed files with 119 additions and 1 deletions

View File

@ -1,3 +1,16 @@
[workspace]
members = ["abstutil", "analyze_code", "control", "convert_osm", "editor", "ezgui", "geom", "headless", "kml", "map_model", "sim"]
members = [
"abstutil",
"analyze_code",
"control",
"convert_osm",
"editor",
"ezgui",
"geom",
"gtfs",
"headless",
"kml",
"map_model",
"sim",
]

View File

@ -547,6 +547,7 @@ Options:
- can we compare results with the prev float approach? make them store the
other thing, compare results? or compare the results of a sim?
- is it possible to do this change gradually? unlikely...
- stick all the types in geom, for now
- moment in time (tick)

9
gtfs/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "gtfs"
version = "0.1.0"
authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
csv = "1.0.1"
failure = "0.1.2"
geom = { path = "../geom" }

87
gtfs/src/lib.rs Normal file
View File

@ -0,0 +1,87 @@
extern crate csv;
extern crate failure;
extern crate geom;
use failure::Error;
use geom::LonLat;
use std::collections::{HashSet, HashMap};
use std::fs::File;
use std::time::Instant;
#[derive(Debug)]
pub struct Route {
name: String,
stops: Vec<LonLat>,
}
pub fn load(dir_path: &str) -> Result<Vec<Route>, Error> {
println!("Loading GTFS from {}", dir_path);
let timer = Instant::now();
let mut route_id_to_name: HashMap<String, String> = HashMap::new();
for rec in csv::Reader::from_reader(File::open(format!("{}/routes.txt", dir_path))?).records() {
let rec = rec?;
route_id_to_name.insert(rec[0].to_string(), rec[2].to_string());
}
let mut stop_id_to_pt: HashMap<String, LonLat> = HashMap::new();
for rec in csv::Reader::from_reader(File::open(format!("{}/stops.txt", dir_path))?).records() {
let rec = rec?;
let lon: f64 = rec[5].parse()?;
let lat: f64 = rec[4].parse()?;
stop_id_to_pt.insert(rec[0].to_string(), LonLat::new(lon, lat));
}
let mut trip_id_to_route_id: HashMap<String, String> = HashMap::new();
for rec in csv::Reader::from_reader(File::open(format!("{}/trips.txt", dir_path))?).records() {
let rec = rec?;
trip_id_to_route_id.insert(rec[2].to_string(), rec[0].to_string());
}
// Each route has many trips. Ignore all but the first and assume the list of stops is the
// same.
let mut route_ids_used: HashSet<String> = HashSet::new();
let mut result: Vec<Route> = Vec::new();
let mut current_trip_id: Option<String> = None;
let mut current_stop_ids: Vec<String> = Vec::new();
for rec in csv::Reader::from_reader(File::open(format!("{}/stop_times.txt", dir_path))?).records() {
let rec = rec?;
// Assume the records are contiguous -- records for one trip are contiguous and sorted by
// stop_sequence already.
if let Some(trip) = current_trip_id.clone() {
if rec[0].to_string() == *trip {
current_stop_ids.push(rec[3].to_string());
} else {
// Save the current route?
let route_id = trip_id_to_route_id[&rec[0]].clone();
if !route_ids_used.contains(&route_id) {
result.push(Route {
name: route_id_to_name[&route_id].clone(),
stops: current_stop_ids.iter().map(|stop_id| stop_id_to_pt[stop_id]).collect(),
});
route_ids_used.insert(route_id);
}
// Reset for the next trip
current_trip_id = Some(rec[0].to_string());
current_stop_ids = vec![rec[3].to_string()];
}
} else {
current_trip_id = Some(rec[0].to_string());
current_stop_ids.push(rec[3].to_string());
}
}
// Handle the last one. TODO duplicates saving code :(
let last_route_id = trip_id_to_route_id[&current_trip_id.unwrap()].clone();
if !route_ids_used.contains(&last_route_id) {
result.push(Route {
name: route_id_to_name[&last_route_id].clone(),
stops: current_stop_ids.iter().map(|stop_id| stop_id_to_pt[stop_id]).collect(),
});
}
let elapsed = timer.elapsed();
let dt = elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) * 1e-9;
println!("Loading GTFS took {}s", dt);
Ok(result)
}

View File

@ -11,6 +11,7 @@ mkdir -p data/input
# https://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_01/N47W122.hgt.zip
# https://data.seattle.gov/api/views/77ms-czxg/rows.json?accessType=DOWNLOAD
# Seattle bounding box is -b=-122.4416,47.5793,-122.2421,47.7155
# https://metro.kingcounty.gov/GTFS/google_transit_2018_18_08.zip
ELEVATION=../data/input/N47W122.hgt
PARCELS_KML=../data/input/King_County_Parcels__parcel_area.kml

View File

@ -12,6 +12,7 @@ dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa
ezgui = { path = "../ezgui" }
failure = "0.1.2"
geom = { path = "../geom" }
gtfs = { path = "../gtfs" }
lazy_static = "1.1.0"
map_model = { path = "../map_model" }
more-asserts = "0.2.1"

View File

@ -1,4 +1,5 @@
use abstutil;
use gtfs;
use control::ControlMap;
use map_model::{BuildingID, BusStop, Edits, LaneID, Map};
use rand::Rng;
@ -12,8 +13,12 @@ pub fn load(
rng_seed: Option<u8>,
savestate_every: Option<Tick>,
) -> (Map, Edits, ControlMap, Sim) {
// Hardcoded files for road edits and transit data.
let edits: Edits = abstutil::read_json("road_edits.json").unwrap_or(Edits::new());
gtfs::load("../data/input/google_transit_2018_18_08").unwrap();
if input.contains("data/save/") {
println!("Resuming from {}", input);
let sim: Sim = abstutil::read_json(&input).expect("loading sim state failed");

View File

@ -11,6 +11,7 @@ extern crate ezgui;
extern crate failure;
extern crate geom;
extern crate graphics;
extern crate gtfs;
#[macro_use]
extern crate lazy_static;
extern crate map_model;

0
test_all.sh Normal file → Executable file
View File