use std::collections::BTreeMap;
use std::fs::File;
use serde::Deserialize;
use abstutil::{MapName, MultiMap};
use geom::{Duration, Time};
use map_model::{BusRouteID, Map};
use sim::Scenario;
use crate::configuration::ImporterConfiguration;
use crate::utils::{download, download_kml, osmconvert};
fn input(config: &ImporterConfiguration, timer: &mut abstutil::Timer) {
download(
config,
"input/seattle/N47W122.hgt",
"https://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_01/N47W122.hgt.zip",
);
download(
config,
"input/seattle/osm/washington-latest.osm.pbf",
"http://download.geofabrik.de/north-america/us/washington-latest.osm.pbf",
);
download(
config,
"input/seattle/parcels_urbansim.txt",
"https://www.dropbox.com/s/t9oug9lwhdwfc04/psrc_2014.zip?dl=0",
);
let bounds = geom::GPSBounds::from(
geom::LonLat::read_osmosis_polygon("importer/config/seattle/huge_seattle.poly").unwrap(),
);
download_kml(
"input/seattle/blockface.bin",
"https://opendata.arcgis.com/datasets/a1458ad1abca41869b81f7c0db0cd777_0.kml",
&bounds,
true,
timer,
);
download_kml(
"input/seattle/offstreet_parking.bin",
"http://data-seattlecitygis.opendata.arcgis.com/datasets/8e52dfde6d5d45948f7a90654c8d50cd_0.kml",
&bounds,
true,
timer
);
download(
config,
"input/seattle/google_transit/",
"http://metro.kingcounty.gov/gtfs/google_transit.zip",
);
}
pub fn osm_to_raw(name: &str, timer: &mut abstutil::Timer, config: &ImporterConfiguration) {
input(config, timer);
osmconvert(
"input/seattle/osm/washington-latest.osm.pbf",
format!("importer/config/seattle/{}.poly", name),
format!("input/seattle/osm/{}.osm", name),
config,
);
let map = convert_osm::convert(
convert_osm::Options {
osm_input: abstutil::path(format!("input/seattle/osm/{}.osm", name)),
name: MapName::seattle(name),
clip: Some(format!("importer/config/seattle/{}.poly", name)),
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::Blockface(abstutil::path(
"input/seattle/blockface.bin",
)),
public_offstreet_parking: convert_osm::PublicOffstreetParking::GIS(abstutil::path(
"input/seattle/offstreet_parking.bin",
)),
private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(
match name {
"downtown" => 5,
"lakeslice" => 3,
"south_seattle" => 5,
"udistrict" => 5,
_ => 1,
},
),
elevation: Some(abstutil::path("input/seattle/N47W122.hgt")),
include_railroads: false,
},
timer,
);
map.save();
}
#[cfg(feature = "scenarios")]
pub fn ensure_popdat_exists(
timer: &mut abstutil::Timer,
config: &ImporterConfiguration,
) -> (crate::soundcast::PopDat, map_model::Map) {
let huge_name = MapName::seattle("huge_seattle");
if abstutil::file_exists(abstutil::path_popdat()) {
println!("- {} exists, not regenerating it", abstutil::path_popdat());
return (
abstutil::read_binary(abstutil::path_popdat(), timer),
map_model::Map::new(huge_name.path(), timer),
);
}
if !abstutil::file_exists(abstutil::path_raw_map(&huge_name)) {
osm_to_raw("huge_seattle", timer, config);
}
let huge_map = if abstutil::file_exists(huge_name.path()) {
map_model::Map::new(huge_name.path(), timer)
} else {
crate::utils::raw_to_map(&huge_name, true, false, timer)
};
(crate::soundcast::import_data(&huge_map, timer), huge_map)
}
pub fn adjust_private_parking(map: &mut Map, scenario: &Scenario) {
for (b, count) in scenario.count_parked_cars_per_bldg().consume() {
map.hack_override_offstreet_spots_individ(b, count);
}
map.save();
}
pub fn add_gtfs_schedules(map: &mut Map) {
let mut trip_marker_to_route: BTreeMap<String, BusRouteID> = BTreeMap::new();
for br in map.all_bus_routes() {
if let Some(ref m) = br.gtfs_trip_marker {
trip_marker_to_route.insert(m.split(":").next().unwrap().to_string(), br.id);
}
}
let mut trip_marker_to_trips: MultiMap<String, String> = MultiMap::new();
for rec in
csv::Reader::from_reader(File::open("data/input/seattle/google_transit/trips.txt").unwrap())
.deserialize()
{
let rec: TripRecord = rec.unwrap();
if trip_marker_to_route.contains_key(&rec.shape_id) {
trip_marker_to_trips.insert(rec.shape_id, rec.trip_id);
}
}
let mut trip_to_earliest_time: BTreeMap<String, Time> = BTreeMap::new();
for rec in csv::Reader::from_reader(
File::open("data/input/seattle/google_transit/stop_times.txt").unwrap(),
)
.deserialize()
{
let rec: StopTimeRecord = rec.unwrap();
let mut time = Time::parse(&rec.arrival_time).unwrap();
if time > Time::START_OF_DAY + Duration::hours(24) {
time = time - Duration::hours(24);
}
if trip_to_earliest_time
.get(&rec.trip_id)
.map(|t| time < *t)
.unwrap_or(true)
{
trip_to_earliest_time.insert(rec.trip_id, time);
}
}
for (marker, trips) in trip_marker_to_trips.consume() {
let mut times = Vec::new();
for trip_id in trips {
times.push(trip_to_earliest_time.remove(&trip_id).unwrap());
}
times.sort();
times.dedup();
let br = trip_marker_to_route.remove(&marker).unwrap();
map.hack_override_orig_spawn_times(br, times);
}
map.save();
}
#[derive(Debug, Deserialize)]
struct TripRecord {
shape_id: String,
trip_id: String,
}
#[derive(Debug, Deserialize)]
struct StopTimeRecord {
trip_id: String,
arrival_time: String,
}