mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 03:35:51 +03:00
some investigation into psrc tour segments again
This commit is contained in:
parent
03d4b4d717
commit
7407e5778f
@ -30,19 +30,6 @@ use std::fmt::Write;
|
|||||||
|
|
||||||
const PROGRESS_FREQUENCY_SECONDS: f64 = 0.2;
|
const PROGRESS_FREQUENCY_SECONDS: f64 = 0.2;
|
||||||
|
|
||||||
// Thanks https://stackoverflow.com/a/49806368
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! skip_fail {
|
|
||||||
($res:expr) => {
|
|
||||||
match $res {
|
|
||||||
Some(val) => val,
|
|
||||||
None => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
|
pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
|
||||||
if x < min {
|
if x < min {
|
||||||
min
|
min
|
||||||
|
@ -165,6 +165,8 @@ d15fe87c4174463e84b9a440162129ed data/system/assets/tools/undo.svg
|
|||||||
512477d8556de48901712165e905782f data/system/assets/tools/locate.svg
|
512477d8556de48901712165e905782f data/system/assets/tools/locate.svg
|
||||||
5f3912d972b47419295ded39c52e647d data/system/assets/tools/next.svg
|
5f3912d972b47419295ded39c52e647d data/system/assets/tools/next.svg
|
||||||
e469148085a2046afd447d31a54d15ab data/system/assets/tools/search.svg
|
e469148085a2046afd447d31a54d15ab data/system/assets/tools/search.svg
|
||||||
|
b9e963ca693bb9329b065454047742e7 data/system/assets/tools/start_pos.svg
|
||||||
|
c8433d44c82e2471ee777c90d4bcd449 data/system/assets/tools/goal_pos.svg
|
||||||
4a5d6456d7c3d9ad94fc1a9e456d6f06 data/system/assets/tools/prev.svg
|
4a5d6456d7c3d9ad94fc1a9e456d6f06 data/system/assets/tools/prev.svg
|
||||||
fe358c0fdf48b65117f7c4970fa35d91 data/system/assets/tools/settings.svg
|
fe358c0fdf48b65117f7c4970fa35d91 data/system/assets/tools/settings.svg
|
||||||
1e0135f13d0aea11650460d6a61b5463 data/system/assets/tools/edit.svg
|
1e0135f13d0aea11650460d6a61b5463 data/system/assets/tools/edit.svg
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use abstutil::{prettyprint_usize, skip_fail, FileWithProgress, Timer};
|
use abstutil::{prettyprint_usize, FileWithProgress, Timer};
|
||||||
use geom::{Distance, Duration, FindClosest, LonLat, Pt2D, Time};
|
use geom::{Distance, Duration, FindClosest, LonLat, Pt2D, Time};
|
||||||
use map_model::Map;
|
use map_model::Map;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
@ -63,30 +63,51 @@ pub fn import_trips(
|
|||||||
trips_path: &str,
|
trips_path: &str,
|
||||||
timer: &mut Timer,
|
timer: &mut Timer,
|
||||||
) -> Result<(Vec<Trip>, BTreeMap<i64, Parcel>), failure::Error> {
|
) -> Result<(Vec<Trip>, BTreeMap<i64, Parcel>), failure::Error> {
|
||||||
let (parcels, metadata) = import_parcels(parcels_path, timer)?;
|
let (parcels, metadata, oob_parcels) = import_parcels(parcels_path, timer)?;
|
||||||
|
|
||||||
let mut trips = Vec::new();
|
let mut trips = Vec::new();
|
||||||
let (reader, done) = FileWithProgress::new(trips_path)?;
|
let (reader, done) = FileWithProgress::new(trips_path)?;
|
||||||
|
let mut total_records = 0;
|
||||||
|
|
||||||
for rec in csv::Reader::from_reader(reader).deserialize() {
|
for rec in csv::Reader::from_reader(reader).deserialize() {
|
||||||
|
total_records += 1;
|
||||||
let rec: RawTrip = rec?;
|
let rec: RawTrip = rec?;
|
||||||
|
|
||||||
let from = skip_fail!(parcels.get(&(rec.opcl as usize))).clone();
|
let from = if let Some(f) = parcels.get(&(rec.opcl as usize)) {
|
||||||
let to = skip_fail!(parcels.get(&(rec.dpcl as usize))).clone();
|
f.clone()
|
||||||
|
} else {
|
||||||
|
if false {
|
||||||
|
println!(
|
||||||
|
"skipping missing from {}",
|
||||||
|
oob_parcels[&(rec.opcl as usize)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let to = if let Some(t) = parcels.get(&(rec.dpcl as usize)) {
|
||||||
|
t.clone()
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
if from.osm_building == to.osm_building {
|
if from.osm_building == to.osm_building {
|
||||||
// TODO Plumb along pass-through trips later
|
// TODO Plumb along pass-through trips later
|
||||||
if from.osm_building.is_some() {
|
if from.osm_building.is_some() {
|
||||||
timer.warn(format!(
|
/*timer.warn(format!(
|
||||||
"Skipping trip from parcel {} to {}; both match OSM building {:?}",
|
"Skipping trip from parcel {} to {}; both match OSM building {:?}",
|
||||||
rec.opcl, rec.dpcl, from.osm_building
|
rec.opcl, rec.dpcl, from.osm_building
|
||||||
));
|
));*/
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let depart_at = Time::START_OF_DAY + Duration::minutes(rec.deptm as usize);
|
let depart_at = Time::START_OF_DAY + Duration::minutes(rec.deptm as usize);
|
||||||
|
|
||||||
let mode = skip_fail!(get_mode(&rec.mode));
|
let mode = if let Some(m) = get_mode(&rec.mode) {
|
||||||
|
m
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
let purpose = (get_purpose(&rec.opurp), get_purpose(&rec.dpurp));
|
let purpose = (get_purpose(&rec.opurp), get_purpose(&rec.dpurp));
|
||||||
|
|
||||||
@ -110,7 +131,11 @@ pub fn import_trips(
|
|||||||
}
|
}
|
||||||
done(timer);
|
done(timer);
|
||||||
|
|
||||||
timer.note(format!("{} trips total", prettyprint_usize(trips.len())));
|
timer.note(format!(
|
||||||
|
"{} trips total. {} records filtered out",
|
||||||
|
prettyprint_usize(trips.len()),
|
||||||
|
prettyprint_usize(total_records - trips.len())
|
||||||
|
));
|
||||||
|
|
||||||
trips.sort_by_key(|t| t.depart_at);
|
trips.sort_by_key(|t| t.depart_at);
|
||||||
|
|
||||||
@ -118,11 +143,19 @@ pub fn import_trips(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Do we also need the zone ID, or is parcel ID globally unique?
|
// TODO Do we also need the zone ID, or is parcel ID globally unique?
|
||||||
// Returns (parcel ID -> Endpoint) and (OSM building ID -> metadata)
|
// Returns (parcel ID -> Endpoint), (OSM building ID -> metadata), and (parcel ID -> LonLat) of
|
||||||
|
// filtered parcels
|
||||||
fn import_parcels(
|
fn import_parcels(
|
||||||
path: &str,
|
path: &str,
|
||||||
timer: &mut Timer,
|
timer: &mut Timer,
|
||||||
) -> Result<(HashMap<usize, Endpoint>, BTreeMap<i64, Parcel>), failure::Error> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
HashMap<usize, Endpoint>,
|
||||||
|
BTreeMap<i64, Parcel>,
|
||||||
|
HashMap<usize, LonLat>,
|
||||||
|
),
|
||||||
|
failure::Error,
|
||||||
|
> {
|
||||||
let map = Map::new(abstutil::path_map("huge_seattle"), false, timer);
|
let map = Map::new(abstutil::path_map("huge_seattle"), false, timer);
|
||||||
|
|
||||||
// TODO I really just want to do polygon containment with a quadtree. FindClosest only does
|
// TODO I really just want to do polygon containment with a quadtree. FindClosest only does
|
||||||
@ -167,9 +200,9 @@ fn import_parcels(
|
|||||||
// cs2cs +init=esri:102748 +to +init=epsg:4326 -f '%.5f' foo
|
// cs2cs +init=esri:102748 +to +init=epsg:4326 -f '%.5f' foo
|
||||||
let output = std::process::Command::new("cs2cs")
|
let output = std::process::Command::new("cs2cs")
|
||||||
.args(vec![
|
.args(vec![
|
||||||
"esri:102748",
|
"+init=esri:102748",
|
||||||
"+to",
|
"+to",
|
||||||
"epsg:4326",
|
"+init=epsg:4326",
|
||||||
"-f",
|
"-f",
|
||||||
"%.5f",
|
"%.5f",
|
||||||
"/tmp/parcels",
|
"/tmp/parcels",
|
||||||
@ -185,6 +218,8 @@ fn import_parcels(
|
|||||||
let reader = BufReader::new(output.stdout.as_slice());
|
let reader = BufReader::new(output.stdout.as_slice());
|
||||||
let mut result = HashMap::new();
|
let mut result = HashMap::new();
|
||||||
let mut metadata = BTreeMap::new();
|
let mut metadata = BTreeMap::new();
|
||||||
|
let mut oob = HashMap::new();
|
||||||
|
let orig_parcels = parcel_metadata.len();
|
||||||
timer.start_iter("read cs2cs output", parcel_metadata.len());
|
timer.start_iter("read cs2cs output", parcel_metadata.len());
|
||||||
for (line, (id, num_households, num_employees, offstreet_parking_spaces)) in
|
for (line, (id, num_households, num_employees, offstreet_parking_spaces)) in
|
||||||
reader.lines().zip(parcel_metadata.into_iter())
|
reader.lines().zip(parcel_metadata.into_iter())
|
||||||
@ -197,7 +232,7 @@ fn import_parcels(
|
|||||||
let pt = LonLat::new(lon, lat);
|
let pt = LonLat::new(lon, lat);
|
||||||
if bounds.contains(pt) {
|
if bounds.contains(pt) {
|
||||||
let osm_building = closest_bldg
|
let osm_building = closest_bldg
|
||||||
.closest_pt(Pt2D::from_gps(pt, bounds).unwrap(), Distance::meters(30.0))
|
.closest_pt(Pt2D::forcibly_from_gps(pt, bounds), Distance::meters(30.0))
|
||||||
.map(|(b, _)| b);
|
.map(|(b, _)| b);
|
||||||
if let Some(b) = osm_building {
|
if let Some(b) = osm_building {
|
||||||
metadata.insert(
|
metadata.insert(
|
||||||
@ -216,9 +251,16 @@ fn import_parcels(
|
|||||||
osm_building,
|
osm_building,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
oob.insert(id, pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((result, metadata))
|
timer.note(format!(
|
||||||
|
"{} parcels. {} filtered out",
|
||||||
|
prettyprint_usize(result.len()),
|
||||||
|
prettyprint_usize(orig_parcels - result.len())
|
||||||
|
));
|
||||||
|
Ok((result, metadata, oob))
|
||||||
}
|
}
|
||||||
|
|
||||||
// From https://github.com/psrc/soundcast/wiki/Outputs#trip-file-_triptsv, opurp and dpurp
|
// From https://github.com/psrc/soundcast/wiki/Outputs#trip-file-_triptsv, opurp and dpurp
|
||||||
@ -244,9 +286,15 @@ fn get_mode(code: &str) -> Option<Mode> {
|
|||||||
match code {
|
match code {
|
||||||
"1.0" => Some(Mode::Walk),
|
"1.0" => Some(Mode::Walk),
|
||||||
"2.0" => Some(Mode::Bike),
|
"2.0" => Some(Mode::Bike),
|
||||||
"6.0" => Some(Mode::Transit),
|
|
||||||
"3.0" | "4.0" | "5.0" => Some(Mode::Drive),
|
"3.0" | "4.0" | "5.0" => Some(Mode::Drive),
|
||||||
_ => None,
|
"6.0" => Some(Mode::Transit),
|
||||||
|
// TODO Park-and-ride!
|
||||||
|
"7.0" => None,
|
||||||
|
// TODO School bus!
|
||||||
|
"8.0" => None,
|
||||||
|
// TODO Invalid code, what's this one mean?
|
||||||
|
"0.0" => None,
|
||||||
|
_ => panic!("Unknown mode {}", code),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,6 +291,7 @@ pub fn trips_to_scenario(map: &Map, timer: &mut Timer) -> Scenario {
|
|||||||
let mut individ_trips: Vec<SpawnTrip> = Vec::new();
|
let mut individ_trips: Vec<SpawnTrip> = Vec::new();
|
||||||
// TODO Don't clone trips for parallelize
|
// TODO Don't clone trips for parallelize
|
||||||
let mut num_ppl = 0;
|
let mut num_ppl = 0;
|
||||||
|
let orig_trips = trips.len();
|
||||||
for (person, list) in timer
|
for (person, list) in timer
|
||||||
.parallelize("turn PSRC trips into SpawnTrips", trips.clone(), |trip| {
|
.parallelize("turn PSRC trips into SpawnTrips", trips.clone(), |trip| {
|
||||||
trip.to_spawn_trip(map)
|
trip.to_spawn_trip(map)
|
||||||
@ -314,9 +315,10 @@ pub fn trips_to_scenario(map: &Map, timer: &mut Timer) -> Scenario {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
timer.note(format!(
|
timer.note(format!(
|
||||||
"{} trips over {} people",
|
"{} trips over {} people. {} trips filtered out",
|
||||||
prettyprint_usize(individ_trips.len()),
|
prettyprint_usize(individ_trips.len()),
|
||||||
prettyprint_usize(num_ppl)
|
prettyprint_usize(num_ppl),
|
||||||
|
prettyprint_usize(orig_trips - individ_trips.len())
|
||||||
));
|
));
|
||||||
|
|
||||||
// How many parked cars do we need to spawn near each building?
|
// How many parked cars do we need to spawn near each building?
|
||||||
|
Loading…
Reference in New Issue
Block a user