Skip to content

Commit

Permalink
When importing external scenario data for cyipt/actdev#32, snap borde…
Browse files Browse the repository at this point in the history
…r endpoints based on the allowed modes of each border. Without this, some driving trips snap to the cycleway next to a road.

212 cancelled trips (that immediately failed) down to 140.
  • Loading branch information
dabreegster committed Jan 16, 2021
1 parent 87f13a0 commit 0a353f6
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 74 deletions.
8 changes: 4 additions & 4 deletions data/MANIFEST.json
Original file line number Diff line number Diff line change
Expand Up @@ -661,14 +661,14 @@
"compressed_size_bytes": 9924393
},
"data/system/cambridge/scenarios/trumpington/baseline.bin": {
"checksum": "b26dd3395d63b23613be2f6e3f596e93",
"checksum": "5f560b95626e8635c00783d26d02be01",
"uncompressed_size_bytes": 71752,
"compressed_size_bytes": 18925
"compressed_size_bytes": 18975
},
"data/system/cambridge/scenarios/trumpington/go_dutch.bin": {
"checksum": "b9af9a890c908f641b5773c50c731cb6",
"checksum": "a943a280ba33228e5b88d41ca9e73939",
"uncompressed_size_bytes": 71752,
"compressed_size_bytes": 18772
"compressed_size_bytes": 18825
},
"data/system/detroit/maps/downtown.bin": {
"checksum": "a582e9865daf7055e676cda6dad1800f",
Expand Down
54 changes: 3 additions & 51 deletions importer/src/soundcast/trips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use abstutil::{prettyprint_usize, MultiMap, Parallelism, Timer};
use geom::LonLat;
use map_model::{osm, BuildingID, IntersectionID, Map, PathConstraints, PathRequest, PathStep};
use sim::{IndividTrip, OrigPersonID, PersonSpec, Scenario, TripEndpoint, TripMode};
use sim::{IndividTrip, MapBorders, OrigPersonID, PersonSpec, Scenario, TripEndpoint, TripMode};

use crate::soundcast::popdat::{Endpoint, OrigTrip, PopDat};

Expand Down Expand Up @@ -134,49 +134,7 @@ fn clip_trips(map: &Map, popdat: &PopDat, huge_map: &Map, timer: &mut Timer) ->
for b in map.all_buildings() {
osm_id_to_bldg.insert(b.orig_id, b.id);
}
let bounds = map.get_gps_bounds();
let incoming_borders_walking: Vec<(IntersectionID, LonLat)> = map
.all_incoming_borders()
.into_iter()
.filter(|i| {
!i.get_outgoing_lanes(map, PathConstraints::Pedestrian)
.is_empty()
})
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let incoming_borders_driving: Vec<(IntersectionID, LonLat)> = map
.all_incoming_borders()
.into_iter()
.filter(|i| !i.get_outgoing_lanes(map, PathConstraints::Car).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let incoming_borders_biking: Vec<(IntersectionID, LonLat)> = map
.all_incoming_borders()
.into_iter()
.filter(|i| !i.get_outgoing_lanes(map, PathConstraints::Bike).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let outgoing_borders_walking: Vec<(IntersectionID, LonLat)> = map
.all_outgoing_borders()
.into_iter()
.filter(|i| {
!i.get_incoming_lanes(map, PathConstraints::Pedestrian)
.is_empty()
})
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let outgoing_borders_driving: Vec<(IntersectionID, LonLat)> = map
.all_outgoing_borders()
.into_iter()
.filter(|i| !i.get_incoming_lanes(map, PathConstraints::Car).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let outgoing_borders_biking: Vec<(IntersectionID, LonLat)> = map
.all_outgoing_borders()
.into_iter()
.filter(|i| !i.get_incoming_lanes(map, PathConstraints::Bike).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let borders = MapBorders::new(map);

let total_trips = popdat.trips.len();
let maybe_results: Vec<Option<Trip>> = timer.parallelize(
Expand All @@ -189,13 +147,7 @@ fn clip_trips(map: &Map, popdat: &PopDat, huge_map: &Map, timer: &mut Timer) ->
&orig.to,
map,
&osm_id_to_bldg,
match orig.mode {
TripMode::Walk | TripMode::Transit => {
(&incoming_borders_walking, &outgoing_borders_walking)
}
TripMode::Drive => (&incoming_borders_driving, &outgoing_borders_driving),
TripMode::Bike => (&incoming_borders_biking, &outgoing_borders_biking),
},
borders.for_mode(orig.mode),
match orig.mode {
TripMode::Walk | TripMode::Transit => PathConstraints::Pedestrian,
TripMode::Drive => PathConstraints::Car,
Expand Down
4 changes: 3 additions & 1 deletion map_editor/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,9 @@ impl Model {
}

fn road_object(&self, id: OriginalRoad) -> Object<ID> {
let (center, total_width) = self.map.roads[&id].get_geometry(id, &self.map.config);
let (center, total_width) = self.map.roads[&id]
.get_geometry(id, &self.map.config)
.unwrap();
Object::new(
ID::Road(id),
Color::grey(0.8),
Expand Down
2 changes: 1 addition & 1 deletion sim/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub(crate) use self::events::Event;
pub use self::events::{AlertLocation, TripPhaseType};
pub use self::make::{
fork_rng, BorderSpawnOverTime, ExternalPerson, ExternalTrip, ExternalTripEndpoint, IndividTrip,
PersonSpec, Scenario, ScenarioGenerator, ScenarioModifier, SimFlags, SpawnOverTime,
MapBorders, PersonSpec, Scenario, ScenarioGenerator, ScenarioModifier, SimFlags, SpawnOverTime,
TripEndpoint, TripPurpose,
};
pub(crate) use self::make::{StartTripArgs, TripSpec};
Expand Down
112 changes: 96 additions & 16 deletions sim/src/make/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use anyhow::Result;
use serde::Deserialize;

use geom::{Distance, FindClosest, LonLat, Time};
use map_model::Map;
use map_model::{IntersectionID, Map, PathConstraints};

use crate::{IndividTrip, PersonSpec, TripEndpoint, TripMode, TripPurpose};

Expand Down Expand Up @@ -39,14 +39,9 @@ impl ExternalPerson {
for b in map.all_buildings() {
closest.add(TripEndpoint::Bldg(b.id), b.polygon.points());
}
let mut borders = Vec::new();
for i in map.all_intersections() {
if i.is_border() {
borders.push((TripEndpoint::Border(i.id), i.polygon.center()));
}
}
let borders = MapBorders::new(map);

let lookup_pt = |endpt| match endpt {
let lookup_pt = |endpt, is_origin, mode| match endpt {
ExternalTripEndpoint::TripEndpoint(endpt) => Ok(endpt),
ExternalTripEndpoint::Position(gps) => {
let pt = gps.to_pt(map.get_gps_bounds());
Expand All @@ -56,12 +51,15 @@ impl ExternalPerson {
None => Err(anyhow!("No building within 100m of {}", gps)),
}
} else {
Ok(borders
.iter()
.min_by_key(|(_, border)| border.fast_dist(pt))
.unwrap()
.0
.clone())
let (incoming, outgoing) = borders.for_mode(mode);
let candidates = if is_origin { incoming } else { outgoing };
Ok(TripEndpoint::Border(
candidates
.iter()
.min_by_key(|(_, border)| border.fast_dist(gps))
.ok_or_else(|| anyhow!("No border for {}", mode.ongoing_verb()))?
.0,
))
}
}
};
Expand All @@ -70,15 +68,17 @@ impl ExternalPerson {
for person in input {
let mut spec = PersonSpec {
orig_id: None,
origin: lookup_pt(person.origin)?,
origin: lookup_pt(person.origin, true, person.trips[0].mode)?,
trips: Vec::new(),
};
for trip in person.trips {
// TODO Add space in the API to specify purpose, but probably make it optional.
spec.trips.push(IndividTrip::new(
trip.departure,
TripPurpose::Shopping,
lookup_pt(trip.destination)?,
// TODO Do we handle somebody going off-map via one one-way bridge, and
// re-entering using the other?
lookup_pt(trip.destination, false, trip.mode)?,
trip.mode,
));
}
Expand All @@ -87,3 +87,83 @@ impl ExternalPerson {
Ok(results)
}
}

pub struct MapBorders {
pub incoming_walking: Vec<(IntersectionID, LonLat)>,
pub incoming_driving: Vec<(IntersectionID, LonLat)>,
pub incoming_biking: Vec<(IntersectionID, LonLat)>,
pub outgoing_walking: Vec<(IntersectionID, LonLat)>,
pub outgoing_driving: Vec<(IntersectionID, LonLat)>,
pub outgoing_biking: Vec<(IntersectionID, LonLat)>,
}

impl MapBorders {
pub fn new(map: &Map) -> MapBorders {
let bounds = map.get_gps_bounds();
let incoming_walking: Vec<(IntersectionID, LonLat)> = map
.all_incoming_borders()
.into_iter()
.filter(|i| {
!i.get_outgoing_lanes(map, PathConstraints::Pedestrian)
.is_empty()
})
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let incoming_driving: Vec<(IntersectionID, LonLat)> = map
.all_incoming_borders()
.into_iter()
.filter(|i| !i.get_outgoing_lanes(map, PathConstraints::Car).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let incoming_biking: Vec<(IntersectionID, LonLat)> = map
.all_incoming_borders()
.into_iter()
.filter(|i| !i.get_outgoing_lanes(map, PathConstraints::Bike).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let outgoing_walking: Vec<(IntersectionID, LonLat)> = map
.all_outgoing_borders()
.into_iter()
.filter(|i| {
!i.get_incoming_lanes(map, PathConstraints::Pedestrian)
.is_empty()
})
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let outgoing_driving: Vec<(IntersectionID, LonLat)> = map
.all_outgoing_borders()
.into_iter()
.filter(|i| !i.get_incoming_lanes(map, PathConstraints::Car).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
let outgoing_biking: Vec<(IntersectionID, LonLat)> = map
.all_outgoing_borders()
.into_iter()
.filter(|i| !i.get_incoming_lanes(map, PathConstraints::Bike).is_empty())
.map(|i| (i.id, i.polygon.center().to_gps(bounds)))
.collect();
MapBorders {
incoming_walking,
incoming_driving,
incoming_biking,
outgoing_walking,
outgoing_driving,
outgoing_biking,
}
}

/// Returns the (incoming, outgoing) borders for the specififed mode.
pub fn for_mode(
&self,
mode: TripMode,
) -> (
&Vec<(IntersectionID, LonLat)>,
&Vec<(IntersectionID, LonLat)>,
) {
match mode {
TripMode::Walk | TripMode::Transit => (&self.incoming_walking, &self.outgoing_walking),
TripMode::Drive => (&self.incoming_driving, &self.outgoing_driving),
TripMode::Bike => (&self.incoming_biking, &self.outgoing_biking),
}
}
}
2 changes: 1 addition & 1 deletion sim/src/make/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use rand::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;

pub use self::external::{ExternalPerson, ExternalTrip, ExternalTripEndpoint};
pub use self::external::{ExternalPerson, ExternalTrip, ExternalTripEndpoint, MapBorders};
pub use self::generator::{BorderSpawnOverTime, ScenarioGenerator, SpawnOverTime};
pub use self::load::SimFlags;
pub use self::modifier::ScenarioModifier;
Expand Down

0 comments on commit 0a353f6

Please sign in to comment.