mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 03:35:51 +03:00
When importing external scenario data for cyipt/actdev#32, snap border 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.
This commit is contained in:
parent
87f13a0d0c
commit
0a353f67f8
@ -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",
|
||||
|
@ -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};
|
||||
|
||||
@ -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(
|
||||
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
||||
@ -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());
|
||||
@ -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,
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -70,7 +68,7 @@ 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 {
|
||||
@ -78,7 +76,9 @@ impl ExternalPerson {
|
||||
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,
|
||||
));
|
||||
}
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user