mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 23:15:24 +03:00
match PSRC trips to OSM building IDs up-front, trimming down filesize and speeding up clipping later
This commit is contained in:
parent
28b2734d59
commit
ea49fe63ba
@ -5,15 +5,15 @@ mod neighborhood;
|
||||
mod scenario;
|
||||
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::DrawOptions;
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::ShowEverything;
|
||||
use crate::ui::UI;
|
||||
use abstutil::Timer;
|
||||
use abstutil::{skip_fail, Timer};
|
||||
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard};
|
||||
use geom::{Circle, Distance, Duration, PolyLine, Pt2D};
|
||||
use geom::{Distance, Duration, PolyLine};
|
||||
use map_model::{BuildingID, Map, PathRequest, Position};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct MissionEditMode {
|
||||
state: State,
|
||||
@ -202,60 +202,35 @@ pub fn clip_trips(
|
||||
max_results: usize,
|
||||
timer: &mut Timer,
|
||||
) -> Vec<Trip> {
|
||||
let mut osm_id_to_bldg = HashMap::new();
|
||||
for b in ui.primary.map.all_buildings() {
|
||||
osm_id_to_bldg.insert(b.osm_way_id, b.id);
|
||||
}
|
||||
|
||||
let mut results = Vec::new();
|
||||
let bounds = ui.primary.map.get_gps_bounds();
|
||||
timer.start_iter("clip trips", popdat.trips.len());
|
||||
for trip in &popdat.trips {
|
||||
timer.next();
|
||||
if results.len() == max_results {
|
||||
continue;
|
||||
}
|
||||
if !bounds.contains(trip.from) || !bounds.contains(trip.to) {
|
||||
continue;
|
||||
}
|
||||
let from = find_building_containing(Pt2D::from_gps(trip.from, bounds).unwrap(), ui);
|
||||
let to = find_building_containing(Pt2D::from_gps(trip.to, bounds).unwrap(), ui);
|
||||
if from.is_some() && to.is_some() {
|
||||
let from = from.unwrap();
|
||||
let to = to.unwrap();
|
||||
if from == to {
|
||||
timer.warn(format!(
|
||||
"Trip leaving at {} goes from {} to {}, both matching {}",
|
||||
trip.depart_at, trip.from, trip.to, from
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push(Trip {
|
||||
from,
|
||||
to,
|
||||
depart_at: trip.depart_at,
|
||||
purpose: trip.purpose,
|
||||
mode: trip.mode,
|
||||
trip_time: trip.trip_time,
|
||||
trip_dist: trip.trip_dist,
|
||||
route: None,
|
||||
});
|
||||
}
|
||||
let from = *skip_fail!(osm_id_to_bldg.get(&trip.from));
|
||||
let to = *skip_fail!(osm_id_to_bldg.get(&trip.to));
|
||||
results.push(Trip {
|
||||
from,
|
||||
to,
|
||||
depart_at: trip.depart_at,
|
||||
purpose: trip.purpose,
|
||||
mode: trip.mode,
|
||||
trip_time: trip.trip_time,
|
||||
trip_dist: trip.trip_dist,
|
||||
route: None,
|
||||
});
|
||||
}
|
||||
results
|
||||
}
|
||||
|
||||
fn find_building_containing(pt: Pt2D, ui: &UI) -> Option<BuildingID> {
|
||||
for obj in ui
|
||||
.primary
|
||||
.draw_map
|
||||
.get_matching_objects(Circle::new(pt, Distance::meters(3.0)).get_bounds())
|
||||
{
|
||||
if let ID::Building(b) = obj {
|
||||
if ui.primary.map.get_b(b).polygon.contains_pt(pt) {
|
||||
return Some(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn instantiate_trips(ctx: &mut EventCtx, ui: &mut UI) {
|
||||
use popdat::psrc::Mode;
|
||||
use sim::{DrivingGoal, Scenario, SidewalkSpot, TripSpec};
|
||||
|
@ -143,11 +143,11 @@ impl DrawMap {
|
||||
for r in map.all_roads().iter() {
|
||||
closest.add(
|
||||
r.id.forwards(),
|
||||
&r.center_pts.shift_right(LANE_THICKNESS).get(timer),
|
||||
r.center_pts.shift_right(LANE_THICKNESS).get(timer).points(),
|
||||
);
|
||||
closest.add(
|
||||
r.id.backwards(),
|
||||
&r.center_pts.shift_left(LANE_THICKNESS).get(timer),
|
||||
r.center_pts.shift_left(LANE_THICKNESS).get(timer).points(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{Bounds, Distance, GPSBounds, LonLat, PolyLine, Pt2D};
|
||||
use crate::{Bounds, Distance, GPSBounds, LonLat, Pt2D};
|
||||
use aabb_quadtree::geom::{Point, Rect};
|
||||
use aabb_quadtree::QuadTree;
|
||||
use geo;
|
||||
@ -22,11 +22,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, key: K, pts: &PolyLine) {
|
||||
self.geometries
|
||||
.insert(key.clone(), pts_to_line_string(&pts.points()));
|
||||
pub fn add(&mut self, key: K, pts: &Vec<Pt2D>) {
|
||||
self.geometries.insert(key.clone(), pts_to_line_string(pts));
|
||||
self.quadtree
|
||||
.insert_with_box(key, pts.get_bounds().as_bbox());
|
||||
.insert_with_box(key, Bounds::from(pts).as_bbox());
|
||||
}
|
||||
|
||||
pub fn add_gps(&mut self, key: K, raw_pts: &Vec<LonLat>, gps_bounds: &GPSBounds) {
|
||||
|
@ -21,7 +21,7 @@ pub fn find_sidewalk_points(
|
||||
for l in lanes {
|
||||
timer.next();
|
||||
if l.is_sidewalk() {
|
||||
closest.add(l.id, &l.lane_center_pts);
|
||||
closest.add(l.id, l.lane_center_pts.points());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,5 +10,6 @@ csv = "1.0.1"
|
||||
failure = "0.1.2"
|
||||
geom = { path = "../geom" }
|
||||
kml = { path = "../kml" }
|
||||
map_model = { path = "../map_model" }
|
||||
serde = "1.0.89"
|
||||
serde_derive = "1.0.89"
|
||||
|
@ -5,14 +5,9 @@ fn main() {
|
||||
// TODO Productionize this.
|
||||
// https://file.ac/cLdO7Hp_OB0/ has trips_2014.csv. https://file.ac/Xdjmi8lb2dA/ has the 2014
|
||||
// inputs.
|
||||
let parcels = popdat::psrc::import_parcels(
|
||||
"/home/dabreegster/Downloads/psrc/2014/landuse/parcels_urbansim.txt",
|
||||
&mut timer,
|
||||
)
|
||||
.unwrap();
|
||||
popdat.trips = popdat::psrc::import_trips(
|
||||
"/home/dabreegster/Downloads/psrc/2014/landuse/parcels_urbansim.txt",
|
||||
"/home/dabreegster/Downloads/psrc/trips_2014.csv",
|
||||
parcels,
|
||||
&mut timer,
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1,5 +1,6 @@
|
||||
use abstutil::{prettyprint_usize, skip_fail, FileWithProgress, Timer};
|
||||
use geom::{Distance, Duration, GPSBounds, LonLat};
|
||||
use geom::{Distance, Duration, FindClosest, LonLat, Pt2D};
|
||||
use map_model::Map;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
@ -7,8 +8,9 @@ use std::io::{BufRead, BufReader, BufWriter, Write};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Trip {
|
||||
pub from: LonLat,
|
||||
pub to: LonLat,
|
||||
// OSM building IDs
|
||||
pub from: i64,
|
||||
pub to: i64,
|
||||
// Relative to midnight
|
||||
pub depart_at: Duration,
|
||||
pub mode: Mode,
|
||||
@ -41,12 +43,14 @@ pub enum Purpose {
|
||||
}
|
||||
|
||||
pub fn import_trips(
|
||||
path: &str,
|
||||
parcels: HashMap<String, LonLat>,
|
||||
parcels_path: &str,
|
||||
trips_path: &str,
|
||||
timer: &mut Timer,
|
||||
) -> Result<Vec<Trip>, failure::Error> {
|
||||
let parcels = import_parcels(parcels_path, timer)?;
|
||||
|
||||
let mut trips = Vec::new();
|
||||
let (reader, done) = FileWithProgress::new(path)?;
|
||||
let (reader, done) = FileWithProgress::new(trips_path)?;
|
||||
for rec in csv::Reader::from_reader(reader).records() {
|
||||
let rec = rec?;
|
||||
|
||||
@ -55,6 +59,14 @@ pub fn import_trips(
|
||||
// dpcl
|
||||
let to = *skip_fail!(parcels.get(rec[6].trim_end_matches(".0")));
|
||||
|
||||
if from == to {
|
||||
timer.warn(format!(
|
||||
"Skipping trip from parcel {} to {}; both match OSM building {}",
|
||||
&rec[15], &rec[6], from
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// deptm
|
||||
let depart_at = Duration::minutes(rec[4].trim_end_matches(".0").parse::<usize>()?);
|
||||
|
||||
@ -84,10 +96,16 @@ pub fn import_trips(
|
||||
}
|
||||
|
||||
// TODO Do we also need the zone ID, or is parcel ID globally unique?
|
||||
pub fn import_parcels(
|
||||
path: &str,
|
||||
timer: &mut Timer,
|
||||
) -> Result<HashMap<String, LonLat>, failure::Error> {
|
||||
fn import_parcels(path: &str, timer: &mut Timer) -> Result<HashMap<String, i64>, failure::Error> {
|
||||
let map: Map = abstutil::read_binary("../data/maps/huge_seattle.abst", timer)?;
|
||||
|
||||
// TODO I really just want to do polygon containment with a quadtree. FindClosest only does
|
||||
// line-string stuff right now, which'll be weird for the last->first pt line and stuff.
|
||||
let mut closest_bldg: FindClosest<i64> = FindClosest::new(map.get_bounds());
|
||||
for b in map.all_buildings() {
|
||||
closest_bldg.add(b.osm_way_id, b.polygon.points());
|
||||
}
|
||||
|
||||
let mut coords = BufWriter::new(File::create("/tmp/parcels")?);
|
||||
let mut parcel_ids = Vec::new();
|
||||
|
||||
@ -128,7 +146,7 @@ pub fn import_parcels(
|
||||
prettyprint_usize(parcel_ids.len())
|
||||
));
|
||||
|
||||
let bounds = GPSBounds::seattle_bounds();
|
||||
let bounds = map.get_gps_bounds();
|
||||
let reader = BufReader::new(output.stdout.as_slice());
|
||||
let mut result = HashMap::new();
|
||||
timer.start_iter("read cs2cs output", parcel_ids.len());
|
||||
@ -140,7 +158,11 @@ pub fn import_parcels(
|
||||
let lat: f64 = pieces[1].parse()?;
|
||||
let pt = LonLat::new(lon, lat);
|
||||
if bounds.contains(pt) {
|
||||
result.insert(id, pt);
|
||||
if let Some((bldg, _)) =
|
||||
closest_bldg.closest_pt(Pt2D::from_gps(pt, bounds).unwrap(), Distance::meters(30.0))
|
||||
{
|
||||
result.insert(id, bldg);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
|
Loading…
Reference in New Issue
Block a user