mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 17:37:22 +03:00
defer choosing a starting lane for borders in scenarios, to respond to lane edits
This commit is contained in:
parent
6d9695fb59
commit
d80513235d
@ -219,15 +219,15 @@ d02d0d103f7b00672a5f1145c5169d8c data/system/fonts/Overpass-Bold.ttf
|
|||||||
cc45f42cb24cad1cfdbf5ed7a0cb86d4 data/system/synthetic_maps/signal_double.json
|
cc45f42cb24cad1cfdbf5ed7a0cb86d4 data/system/synthetic_maps/signal_double.json
|
||||||
8b949cc34d9a27ace0bd8ecde55a9520 data/system/synthetic_maps/signal_single.json
|
8b949cc34d9a27ace0bd8ecde55a9520 data/system/synthetic_maps/signal_single.json
|
||||||
1cd7be125e1d992613ed3a41e8b25b6a data/system/synthetic_maps/signal_fan_in.json
|
1cd7be125e1d992613ed3a41e8b25b6a data/system/synthetic_maps/signal_fan_in.json
|
||||||
dc7d7c8b8dec9c2d0375df3ed0c02d87 data/system/scenarios/ballard/weekday.bin
|
1d447747aa2e493310abe5e103a1f693 data/system/scenarios/ballard/weekday.bin
|
||||||
ec3d36603a91a1b61a63823404ad16d6 data/system/scenarios/intl_district/weekday.bin
|
a72c52c5493d3d7eeaec296ffc7025a2 data/system/scenarios/intl_district/weekday.bin
|
||||||
34f366fc48867dc4d923fc638e804af0 data/system/scenarios/23rd/weekday.bin
|
86603a31ee66b91ebb4a66e1146a3b17 data/system/scenarios/23rd/weekday.bin
|
||||||
bca018492766b536680a6aae9592d397 data/system/scenarios/downtown/weekday.bin
|
17a1f28e4418937ff17504e357206b8c data/system/scenarios/downtown/weekday.bin
|
||||||
354a0d31dd19b31fe4599233a2057c41 data/system/scenarios/huge_seattle/weekday.bin
|
afb0ab6073cd6439ccaa41addd3de68b data/system/scenarios/huge_seattle/weekday.bin
|
||||||
60712719b44a47cc6accf97d069fac92 data/system/scenarios/caphill/weekday.bin
|
248f2874b28dfda11cb052e53ef51414 data/system/scenarios/caphill/weekday.bin
|
||||||
8e38d4e4a93beb7080029dcb76d47563 data/system/scenarios/montlake/weekday.bin
|
bf0bef6566fb918db5c9ad3e9054731a data/system/scenarios/montlake/weekday.bin
|
||||||
ad5d2c7a2c73ef5bf4a09ff11845c166 data/system/prebaked_results/signal_single/tutorial lvl1.bin
|
3e4614071e27205513a5cc9b7fc11c90 data/system/prebaked_results/signal_single/tutorial lvl1.bin
|
||||||
81081122aa46e8651d8f07bb606bc77a data/system/prebaked_results/signal_single/tutorial lvl2.bin
|
eb732e116af8c64cd879e9acb1b2eb1f data/system/prebaked_results/signal_single/tutorial lvl2.bin
|
||||||
e15dd2d01fccadb1f16c4ed9f732b377 data/system/prebaked_results/montlake/car vs bike contention.bin
|
9577e253b4fa810edef68f3dd8860ff0 data/system/prebaked_results/montlake/car vs bike contention.bin
|
||||||
1f1314220db40c778c18cd03e9af5d18 data/system/prebaked_results/montlake/weekday.bin
|
de9631bca160dea190cc23e5ac0b7139 data/system/prebaked_results/montlake/weekday.bin
|
||||||
ba713f7f6ad0c0201f1447d77957ce75 data/system/prebaked_results/montlake/car vs bus contention.bin
|
b4a1a7f94385434dce3fb71b82e403e3 data/system/prebaked_results/montlake/car vs bus contention.bin
|
||||||
|
@ -280,6 +280,14 @@ fn describe(person: &PersonSpec, trip: &IndividTrip, home: OD) -> String {
|
|||||||
start.lane(),
|
start.lane(),
|
||||||
driving_goal(goal)
|
driving_goal(goal)
|
||||||
),
|
),
|
||||||
|
SpawnTrip::FromBorder { i, goal, is_bike } => format!(
|
||||||
|
"{} at {}: {} appears at {}, goes to {}",
|
||||||
|
person.id,
|
||||||
|
trip.depart,
|
||||||
|
if *is_bike { "bike" } else { "car" },
|
||||||
|
i,
|
||||||
|
driving_goal(goal)
|
||||||
|
),
|
||||||
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => format!(
|
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => format!(
|
||||||
"{} at {}: try to drive from {} to {}",
|
"{} at {}: try to drive from {} to {}",
|
||||||
person.id,
|
person.id,
|
||||||
@ -332,6 +340,7 @@ fn other_endpt(trip: &IndividTrip, home: OD, map: &Map) -> ID {
|
|||||||
ID::Intersection(map.get_l(start.lane()).src_i),
|
ID::Intersection(map.get_l(start.lane()).src_i),
|
||||||
driving_goal(goal),
|
driving_goal(goal),
|
||||||
),
|
),
|
||||||
|
SpawnTrip::FromBorder { i, goal, .. } => (ID::Intersection(*i), driving_goal(goal)),
|
||||||
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => {
|
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => {
|
||||||
(ID::Building(*start_bldg), driving_goal(goal))
|
(ID::Building(*start_bldg), driving_goal(goal))
|
||||||
}
|
}
|
||||||
@ -445,6 +454,9 @@ impl DotMap {
|
|||||||
SpawnTrip::CarAppearing { start, goal, .. } => {
|
SpawnTrip::CarAppearing { start, goal, .. } => {
|
||||||
(start.pt(map), goal.pt(map))
|
(start.pt(map), goal.pt(map))
|
||||||
}
|
}
|
||||||
|
SpawnTrip::FromBorder { i, goal, .. } => {
|
||||||
|
(map.get_i(*i).polygon.center(), goal.pt(map))
|
||||||
|
}
|
||||||
SpawnTrip::MaybeUsingParkedCar(b, goal) => {
|
SpawnTrip::MaybeUsingParkedCar(b, goal) => {
|
||||||
(map.get_b(*b).polygon.center(), goal.pt(map))
|
(map.get_b(*b).polygon.center(), goal.pt(map))
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ fn schedule_trip(
|
|||||||
};
|
};
|
||||||
match src {
|
match src {
|
||||||
Source::Drive(from) => {
|
Source::Drive(from) => {
|
||||||
if let Some(start_pos) = TripSpec::spawn_car_at(*from, map) {
|
if let Some(start_pos) = TripSpec::spawn_vehicle_at(*from, false, map) {
|
||||||
spawner.schedule_trip(
|
spawner.schedule_trip(
|
||||||
sim.random_person(true),
|
sim.random_person(true),
|
||||||
sim.time(),
|
sim.time(),
|
||||||
|
@ -68,12 +68,18 @@ impl Intersection {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strict for bikes. If there are bike lanes, not allowed to use other lanes.
|
||||||
pub fn get_outgoing_lanes(&self, map: &Map, constraints: PathConstraints) -> Vec<LaneID> {
|
pub fn get_outgoing_lanes(&self, map: &Map, constraints: PathConstraints) -> Vec<LaneID> {
|
||||||
self.outgoing_lanes
|
let mut choices: Vec<LaneID> = self
|
||||||
|
.outgoing_lanes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|l| constraints.can_use(map.get_l(**l), map))
|
.filter(|l| constraints.can_use(map.get_l(**l), map))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect();
|
||||||
|
if constraints == PathConstraints::Bike {
|
||||||
|
choices.retain(|l| map.get_l(*l).is_biking());
|
||||||
|
}
|
||||||
|
choices
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_zorder(&self, map: &Map) -> isize {
|
pub fn get_zorder(&self, map: &Map) -> isize {
|
||||||
|
@ -2,10 +2,8 @@ use crate::psrc::{Endpoint, Mode, Parcel, Purpose};
|
|||||||
use crate::PopDat;
|
use crate::PopDat;
|
||||||
use abstutil::{prettyprint_usize, MultiMap, Timer};
|
use abstutil::{prettyprint_usize, MultiMap, Timer};
|
||||||
use geom::{Distance, Duration, LonLat, Polygon, Pt2D, Time};
|
use geom::{Distance, Duration, LonLat, Polygon, Pt2D, Time};
|
||||||
use map_model::{BuildingID, IntersectionID, Map, PathConstraints, Position};
|
use map_model::{BuildingID, IntersectionID, Map, PathConstraints};
|
||||||
use sim::{
|
use sim::{DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip};
|
||||||
DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip, TripSpec,
|
|
||||||
};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -37,72 +35,45 @@ impl Trip {
|
|||||||
self.depart_at + self.trip_time
|
self.depart_at + self.trip_time
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_spawn_trip(&self, map: &Map) -> Option<SpawnTrip> {
|
fn to_spawn_trip(&self, map: &Map) -> SpawnTrip {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::Drive => match self.from {
|
Mode::Drive => match self.from {
|
||||||
TripEndpt::Border(i, _) => {
|
TripEndpt::Border(i, _) => SpawnTrip::FromBorder {
|
||||||
if let Some(start) = TripSpec::spawn_car_at(
|
i,
|
||||||
Position::new(
|
goal: self.to.driving_goal(PathConstraints::Car, map),
|
||||||
map.get_i(i).get_outgoing_lanes(map, PathConstraints::Car)[0],
|
is_bike: false,
|
||||||
Distance::ZERO,
|
},
|
||||||
),
|
TripEndpt::Building(b) => SpawnTrip::MaybeUsingParkedCar(
|
||||||
map,
|
|
||||||
) {
|
|
||||||
Some(SpawnTrip::CarAppearing {
|
|
||||||
start,
|
|
||||||
goal: self.to.driving_goal(PathConstraints::Car, map),
|
|
||||||
is_bike: false,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// TODO need to be able to emit warnings from parallelize
|
|
||||||
//timer.warn(format!("No room for car to appear at {:?}", self.from));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TripEndpt::Building(b) => Some(SpawnTrip::MaybeUsingParkedCar(
|
|
||||||
b,
|
b,
|
||||||
self.to.driving_goal(PathConstraints::Car, map),
|
self.to.driving_goal(PathConstraints::Car, map),
|
||||||
)),
|
),
|
||||||
},
|
},
|
||||||
Mode::Bike => match self.from {
|
Mode::Bike => match self.from {
|
||||||
TripEndpt::Building(b) => Some(SpawnTrip::UsingBike(
|
TripEndpt::Building(b) => SpawnTrip::UsingBike(
|
||||||
SidewalkSpot::building(b, map),
|
SidewalkSpot::building(b, map),
|
||||||
self.to.driving_goal(PathConstraints::Bike, map),
|
self.to.driving_goal(PathConstraints::Bike, map),
|
||||||
)),
|
),
|
||||||
TripEndpt::Border(i, _) => {
|
TripEndpt::Border(i, _) => SpawnTrip::FromBorder {
|
||||||
if let Some(start) = TripSpec::spawn_car_at(
|
i,
|
||||||
Position::new(
|
goal: self.to.driving_goal(PathConstraints::Bike, map),
|
||||||
map.get_i(i).get_outgoing_lanes(map, PathConstraints::Bike)[0],
|
is_bike: true,
|
||||||
Distance::ZERO,
|
},
|
||||||
),
|
|
||||||
map,
|
|
||||||
) {
|
|
||||||
Some(SpawnTrip::CarAppearing {
|
|
||||||
start,
|
|
||||||
goal: self.to.driving_goal(PathConstraints::Bike, map),
|
|
||||||
is_bike: true,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
//timer.warn(format!("No room for bike to appear at {:?}", self.from));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Mode::Walk => Some(SpawnTrip::JustWalking(
|
Mode::Walk => SpawnTrip::JustWalking(
|
||||||
self.from.start_sidewalk_spot(map),
|
self.from.start_sidewalk_spot(map),
|
||||||
self.to.end_sidewalk_spot(map),
|
self.to.end_sidewalk_spot(map),
|
||||||
)),
|
),
|
||||||
Mode::Transit => {
|
Mode::Transit => {
|
||||||
let start = self.from.start_sidewalk_spot(map);
|
let start = self.from.start_sidewalk_spot(map);
|
||||||
let goal = self.to.end_sidewalk_spot(map);
|
let goal = self.to.end_sidewalk_spot(map);
|
||||||
if let Some((stop1, stop2, route)) =
|
if let Some((stop1, stop2, route)) =
|
||||||
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
||||||
{
|
{
|
||||||
Some(SpawnTrip::UsingTransit(start, goal, route, stop1, stop2))
|
SpawnTrip::UsingTransit(start, goal, route, stop1, stop2)
|
||||||
} else {
|
} else {
|
||||||
//timer.warn(format!("{:?} not actually using transit, because pathfinding
|
//timer.warn(format!("{:?} not actually using transit, because pathfinding
|
||||||
// didn't find any useful route", trip));
|
// didn't find any useful route", trip));
|
||||||
Some(SpawnTrip::JustWalking(start, goal))
|
SpawnTrip::JustWalking(start, goal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,13 +260,15 @@ pub fn trips_to_scenario(map: &Map, timer: &mut Timer) -> Scenario {
|
|||||||
// person -> (trip seq, index into individ_trips)
|
// person -> (trip seq, index into individ_trips)
|
||||||
let mut trips_per_person: MultiMap<(usize, usize), ((usize, bool, usize), usize)> =
|
let mut trips_per_person: MultiMap<(usize, usize), ((usize, bool, usize), usize)> =
|
||||||
MultiMap::new();
|
MultiMap::new();
|
||||||
for (trip, depart, person, seq) in timer
|
for (trip, depart, person, seq) in
|
||||||
.parallelize("turn PSRC trips into SpawnTrips", trips, |trip| {
|
timer.parallelize("turn PSRC trips into SpawnTrips", trips, |trip| {
|
||||||
trip.to_spawn_trip(map)
|
(
|
||||||
.map(|spawn| (spawn, trip.depart_at, trip.person, trip.seq))
|
trip.to_spawn_trip(map),
|
||||||
|
trip.depart_at,
|
||||||
|
trip.person,
|
||||||
|
trip.seq,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
{
|
{
|
||||||
let idx = individ_trips.len();
|
let idx = individ_trips.len();
|
||||||
individ_trips.push(Some(IndividTrip { depart, trip }));
|
individ_trips.push(Some(IndividTrip { depart, trip }));
|
||||||
@ -324,7 +297,7 @@ pub fn trips_to_scenario(map: &Map, timer: &mut Timer) -> Scenario {
|
|||||||
let mut has_car = false;
|
let mut has_car = false;
|
||||||
for trip in &trips {
|
for trip in &trips {
|
||||||
match trip.trip {
|
match trip.trip {
|
||||||
SpawnTrip::CarAppearing { is_bike, .. } => {
|
SpawnTrip::FromBorder { is_bike, .. } => {
|
||||||
if !is_bike {
|
if !is_bike {
|
||||||
has_car = true;
|
has_car = true;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
use crate::{
|
use crate::{DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip};
|
||||||
DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip, BIKE_LENGTH,
|
|
||||||
MAX_CAR_LENGTH,
|
|
||||||
};
|
|
||||||
use abstutil::Timer;
|
use abstutil::Timer;
|
||||||
use geom::{Duration, Time};
|
use geom::{Duration, Time};
|
||||||
use map_model::{
|
use map_model::{BuildingID, DirectedRoadID, FullNeighborhoodInfo, Map, PathConstraints};
|
||||||
BuildingID, DirectedRoadID, FullNeighborhoodInfo, LaneID, Map, PathConstraints, Position,
|
|
||||||
};
|
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
@ -80,8 +75,24 @@ impl ScenarioGenerator {
|
|||||||
for s in &self.border_spawn_over_time {
|
for s in &self.border_spawn_over_time {
|
||||||
timer.next();
|
timer.next();
|
||||||
s.spawn_peds(rng, &mut scenario, &neighborhoods, map, timer);
|
s.spawn_peds(rng, &mut scenario, &neighborhoods, map, timer);
|
||||||
s.spawn_cars(rng, &mut scenario, &neighborhoods, map, timer);
|
s.spawn_vehicles(
|
||||||
s.spawn_bikes(rng, &mut scenario, &neighborhoods, map, timer);
|
s.num_cars,
|
||||||
|
PathConstraints::Car,
|
||||||
|
rng,
|
||||||
|
&mut scenario,
|
||||||
|
&neighborhoods,
|
||||||
|
map,
|
||||||
|
timer,
|
||||||
|
);
|
||||||
|
s.spawn_vehicles(
|
||||||
|
s.num_bikes,
|
||||||
|
PathConstraints::Bike,
|
||||||
|
rng,
|
||||||
|
&mut scenario,
|
||||||
|
&neighborhoods,
|
||||||
|
map,
|
||||||
|
timer,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.stop(format!("Generating scenario {}", self.scenario_name));
|
timer.stop(format!("Generating scenario {}", self.scenario_name));
|
||||||
@ -327,97 +338,34 @@ impl BorderSpawnOverTime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_cars(
|
fn spawn_vehicles(
|
||||||
&self,
|
&self,
|
||||||
|
num: usize,
|
||||||
|
constraints: PathConstraints,
|
||||||
rng: &mut XorShiftRng,
|
rng: &mut XorShiftRng,
|
||||||
scenario: &mut Scenario,
|
scenario: &mut Scenario,
|
||||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
timer: &mut Timer,
|
timer: &mut Timer,
|
||||||
) {
|
) {
|
||||||
if self.num_cars == 0 {
|
for _ in 0..num {
|
||||||
return;
|
|
||||||
}
|
|
||||||
let lanes = pick_starting_lanes(
|
|
||||||
self.start_from_border.lanes(PathConstraints::Car, map),
|
|
||||||
false,
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
if lanes.is_empty() {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Can't start {} cars at border for {}",
|
|
||||||
self.num_cars, self.start_from_border
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
for _ in 0..self.num_cars {
|
|
||||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||||
if let Some(goal) =
|
if let Some(goal) =
|
||||||
self.goal
|
self.goal
|
||||||
.pick_driving_goal(PathConstraints::Car, map, &neighborhoods, rng, timer)
|
.pick_driving_goal(constraints, map, &neighborhoods, rng, timer)
|
||||||
{
|
{
|
||||||
let id = PersonID(scenario.people.len());
|
let id = PersonID(scenario.people.len());
|
||||||
scenario.people.push(PersonSpec {
|
scenario.people.push(PersonSpec {
|
||||||
id,
|
id,
|
||||||
trips: vec![IndividTrip {
|
trips: vec![IndividTrip {
|
||||||
depart,
|
depart,
|
||||||
trip: SpawnTrip::CarAppearing {
|
trip: SpawnTrip::FromBorder {
|
||||||
// Safe because pick_starting_lanes checks for this
|
i: self.start_from_border.src_i(map),
|
||||||
start: Position::new(*lanes.choose(rng).unwrap(), MAX_CAR_LENGTH),
|
|
||||||
goal,
|
goal,
|
||||||
is_bike: false,
|
is_bike: constraints == PathConstraints::Bike,
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
has_car: true,
|
has_car: constraints == PathConstraints::Car,
|
||||||
car_initially_parked_at: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_bikes(
|
|
||||||
&self,
|
|
||||||
rng: &mut XorShiftRng,
|
|
||||||
scenario: &mut Scenario,
|
|
||||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
|
||||||
map: &Map,
|
|
||||||
timer: &mut Timer,
|
|
||||||
) {
|
|
||||||
if self.num_bikes == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let lanes = pick_starting_lanes(
|
|
||||||
self.start_from_border.lanes(PathConstraints::Bike, map),
|
|
||||||
true,
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
if lanes.is_empty() {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Can't start {} bikes at border for {}",
|
|
||||||
self.num_bikes, self.start_from_border
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
for _ in 0..self.num_bikes {
|
|
||||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
|
||||||
if let Some(goal) =
|
|
||||||
self.goal
|
|
||||||
.pick_driving_goal(PathConstraints::Bike, map, &neighborhoods, rng, timer)
|
|
||||||
{
|
|
||||||
let id = PersonID(scenario.people.len());
|
|
||||||
scenario.people.push(PersonSpec {
|
|
||||||
id,
|
|
||||||
trips: vec![IndividTrip {
|
|
||||||
depart,
|
|
||||||
trip: SpawnTrip::CarAppearing {
|
|
||||||
start: Position::new(*lanes.choose(rng).unwrap(), BIKE_LENGTH),
|
|
||||||
goal,
|
|
||||||
is_bike: true,
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
has_car: false,
|
|
||||||
car_initially_parked_at: None,
|
car_initially_parked_at: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -487,22 +435,3 @@ fn rand_time(rng: &mut XorShiftRng, low: Time, high: Time) -> Time {
|
|||||||
assert!(high > low);
|
assert!(high > low);
|
||||||
Time::START_OF_DAY + Duration::seconds(rng.gen_range(low.inner_seconds(), high.inner_seconds()))
|
Time::START_OF_DAY + Duration::seconds(rng.gen_range(low.inner_seconds(), high.inner_seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_starting_lanes(mut lanes: Vec<LaneID>, is_bike: bool, map: &Map) -> Vec<LaneID> {
|
|
||||||
let min_len = if is_bike { BIKE_LENGTH } else { MAX_CAR_LENGTH };
|
|
||||||
lanes.retain(|l| map.get_l(*l).length() > min_len);
|
|
||||||
|
|
||||||
if is_bike {
|
|
||||||
// If there's a choice between bike lanes and otherwise, always use the bike lanes.
|
|
||||||
let bike_lanes = lanes
|
|
||||||
.iter()
|
|
||||||
.filter(|l| map.get_l(**l).is_biking())
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<LaneID>>();
|
|
||||||
if !bike_lanes.is_empty() {
|
|
||||||
lanes = bike_lanes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lanes
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use abstutil::{MultiMap, Timer};
|
use abstutil::{MultiMap, Timer};
|
||||||
use geom::{Distance, Duration, Speed, Time};
|
use geom::{Distance, Duration, Speed, Time};
|
||||||
use map_model::{BuildingID, BusRouteID, BusStopID, IntersectionID, Map, Position, RoadID};
|
use map_model::{
|
||||||
|
BuildingID, BusRouteID, BusStopID, IntersectionID, Map, PathConstraints, Position, RoadID,
|
||||||
|
};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
@ -39,11 +41,16 @@ pub struct IndividTrip {
|
|||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
pub enum SpawnTrip {
|
pub enum SpawnTrip {
|
||||||
|
// Only for interactive / debug trips
|
||||||
CarAppearing {
|
CarAppearing {
|
||||||
// TODO Replace start with building|border
|
|
||||||
start: Position,
|
start: Position,
|
||||||
goal: DrivingGoal,
|
goal: DrivingGoal,
|
||||||
// For bikes starting at a border, use CarAppearing. UsingBike implies a walk->bike trip.
|
is_bike: bool,
|
||||||
|
},
|
||||||
|
FromBorder {
|
||||||
|
i: IntersectionID,
|
||||||
|
goal: DrivingGoal,
|
||||||
|
// For bikes starting at a border, use FromBorder. UsingBike implies a walk->bike trip.
|
||||||
is_bike: bool,
|
is_bike: bool,
|
||||||
},
|
},
|
||||||
MaybeUsingParkedCar(BuildingID, DrivingGoal),
|
MaybeUsingParkedCar(BuildingID, DrivingGoal),
|
||||||
@ -90,9 +97,14 @@ impl Scenario {
|
|||||||
// TODO Or spawner?
|
// TODO Or spawner?
|
||||||
sim.new_person(p.id, p.has_car);
|
sim.new_person(p.id, p.has_car);
|
||||||
for t in &p.trips {
|
for t in &p.trips {
|
||||||
// The RNG call is stable over edits.
|
// The RNG call might change over edits for picking the spawning lane from a border
|
||||||
let spec = t.trip.clone().to_trip_spec(rng);
|
// with multiple choices for a vehicle type.
|
||||||
spawner.schedule_trip(p.id, t.depart, spec, map, sim);
|
let mut tmp_rng = abstutil::fork_rng(rng);
|
||||||
|
if let Some(spec) = t.trip.clone().to_trip_spec(&mut tmp_rng, map) {
|
||||||
|
spawner.schedule_trip(p.id, t.depart, spec, map, sim);
|
||||||
|
} else {
|
||||||
|
timer.warn(format!("Couldn't turn {:?} into a trip", t.trip));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,14 +306,14 @@ fn find_spot_near_building(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SpawnTrip {
|
impl SpawnTrip {
|
||||||
fn to_trip_spec(self, rng: &mut XorShiftRng) -> TripSpec {
|
fn to_trip_spec(self, rng: &mut XorShiftRng, map: &Map) -> Option<TripSpec> {
|
||||||
match self {
|
match self {
|
||||||
SpawnTrip::CarAppearing {
|
SpawnTrip::CarAppearing {
|
||||||
start,
|
start,
|
||||||
goal,
|
goal,
|
||||||
is_bike,
|
is_bike,
|
||||||
..
|
..
|
||||||
} => TripSpec::CarAppearing {
|
} => Some(TripSpec::CarAppearing {
|
||||||
start_pos: start,
|
start_pos: start,
|
||||||
goal,
|
goal,
|
||||||
vehicle_spec: if is_bike {
|
vehicle_spec: if is_bike {
|
||||||
@ -310,37 +322,67 @@ impl SpawnTrip {
|
|||||||
Scenario::rand_car(rng)
|
Scenario::rand_car(rng)
|
||||||
},
|
},
|
||||||
ped_speed: Scenario::rand_ped_speed(rng),
|
ped_speed: Scenario::rand_ped_speed(rng),
|
||||||
},
|
}),
|
||||||
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => TripSpec::MaybeUsingParkedCar {
|
SpawnTrip::FromBorder {
|
||||||
start_bldg,
|
i, goal, is_bike, ..
|
||||||
|
} => Some(TripSpec::CarAppearing {
|
||||||
|
start_pos: {
|
||||||
|
let l = *map
|
||||||
|
.get_i(i)
|
||||||
|
.get_outgoing_lanes(
|
||||||
|
map,
|
||||||
|
if is_bike {
|
||||||
|
PathConstraints::Bike
|
||||||
|
} else {
|
||||||
|
PathConstraints::Car
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.choose(rng)?;
|
||||||
|
TripSpec::spawn_vehicle_at(Position::new(l, Distance::ZERO), is_bike, map)?
|
||||||
|
},
|
||||||
goal,
|
goal,
|
||||||
|
vehicle_spec: if is_bike {
|
||||||
|
Scenario::rand_bike(rng)
|
||||||
|
} else {
|
||||||
|
Scenario::rand_car(rng)
|
||||||
|
},
|
||||||
ped_speed: Scenario::rand_ped_speed(rng),
|
ped_speed: Scenario::rand_ped_speed(rng),
|
||||||
},
|
}),
|
||||||
SpawnTrip::UsingBike(start, goal) => TripSpec::UsingBike {
|
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => {
|
||||||
|
Some(TripSpec::MaybeUsingParkedCar {
|
||||||
|
start_bldg,
|
||||||
|
goal,
|
||||||
|
ped_speed: Scenario::rand_ped_speed(rng),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
SpawnTrip::UsingBike(start, goal) => Some(TripSpec::UsingBike {
|
||||||
start,
|
start,
|
||||||
goal,
|
goal,
|
||||||
vehicle: Scenario::rand_bike(rng),
|
vehicle: Scenario::rand_bike(rng),
|
||||||
ped_speed: Scenario::rand_ped_speed(rng),
|
ped_speed: Scenario::rand_ped_speed(rng),
|
||||||
},
|
}),
|
||||||
SpawnTrip::JustWalking(start, goal) => TripSpec::JustWalking {
|
SpawnTrip::JustWalking(start, goal) => Some(TripSpec::JustWalking {
|
||||||
start,
|
start,
|
||||||
goal,
|
goal,
|
||||||
ped_speed: Scenario::rand_ped_speed(rng),
|
ped_speed: Scenario::rand_ped_speed(rng),
|
||||||
},
|
}),
|
||||||
SpawnTrip::UsingTransit(start, goal, route, stop1, stop2) => TripSpec::UsingTransit {
|
SpawnTrip::UsingTransit(start, goal, route, stop1, stop2) => {
|
||||||
start,
|
Some(TripSpec::UsingTransit {
|
||||||
goal,
|
start,
|
||||||
route,
|
goal,
|
||||||
stop1,
|
route,
|
||||||
stop2,
|
stop1,
|
||||||
ped_speed: Scenario::rand_ped_speed(rng),
|
stop2,
|
||||||
},
|
ped_speed: Scenario::rand_ped_speed(rng),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_from_bldg(&self) -> Option<BuildingID> {
|
pub fn start_from_bldg(&self) -> Option<BuildingID> {
|
||||||
match self {
|
match self {
|
||||||
SpawnTrip::CarAppearing { .. } => None,
|
SpawnTrip::CarAppearing { .. } => None,
|
||||||
|
SpawnTrip::FromBorder { .. } => None,
|
||||||
SpawnTrip::MaybeUsingParkedCar(b, _) => Some(*b),
|
SpawnTrip::MaybeUsingParkedCar(b, _) => Some(*b),
|
||||||
SpawnTrip::UsingBike(ref spot, _)
|
SpawnTrip::UsingBike(ref spot, _)
|
||||||
| SpawnTrip::JustWalking(ref spot, _)
|
| SpawnTrip::JustWalking(ref spot, _)
|
||||||
@ -353,8 +395,8 @@ impl SpawnTrip {
|
|||||||
|
|
||||||
pub fn start_from_border(&self) -> Option<IntersectionID> {
|
pub fn start_from_border(&self) -> Option<IntersectionID> {
|
||||||
match self {
|
match self {
|
||||||
// TODO CarAppearing might be from a border
|
|
||||||
SpawnTrip::CarAppearing { .. } => None,
|
SpawnTrip::CarAppearing { .. } => None,
|
||||||
|
SpawnTrip::FromBorder { i, .. } => Some(*i),
|
||||||
SpawnTrip::MaybeUsingParkedCar(_, _) => None,
|
SpawnTrip::MaybeUsingParkedCar(_, _) => None,
|
||||||
SpawnTrip::UsingBike(ref spot, _)
|
SpawnTrip::UsingBike(ref spot, _)
|
||||||
| SpawnTrip::JustWalking(ref spot, _)
|
| SpawnTrip::JustWalking(ref spot, _)
|
||||||
@ -368,6 +410,7 @@ impl SpawnTrip {
|
|||||||
pub fn end_at_bldg(&self) -> Option<BuildingID> {
|
pub fn end_at_bldg(&self) -> Option<BuildingID> {
|
||||||
match self {
|
match self {
|
||||||
SpawnTrip::CarAppearing { ref goal, .. }
|
SpawnTrip::CarAppearing { ref goal, .. }
|
||||||
|
| SpawnTrip::FromBorder { ref goal, .. }
|
||||||
| SpawnTrip::MaybeUsingParkedCar(_, ref goal)
|
| SpawnTrip::MaybeUsingParkedCar(_, ref goal)
|
||||||
| SpawnTrip::UsingBike(_, ref goal) => match goal {
|
| SpawnTrip::UsingBike(_, ref goal) => match goal {
|
||||||
DrivingGoal::ParkNear(b) => Some(*b),
|
DrivingGoal::ParkNear(b) => Some(*b),
|
||||||
@ -385,6 +428,7 @@ impl SpawnTrip {
|
|||||||
pub fn end_at_border(&self) -> Option<IntersectionID> {
|
pub fn end_at_border(&self) -> Option<IntersectionID> {
|
||||||
match self {
|
match self {
|
||||||
SpawnTrip::CarAppearing { ref goal, .. }
|
SpawnTrip::CarAppearing { ref goal, .. }
|
||||||
|
| SpawnTrip::FromBorder { ref goal, .. }
|
||||||
| SpawnTrip::MaybeUsingParkedCar(_, ref goal)
|
| SpawnTrip::MaybeUsingParkedCar(_, ref goal)
|
||||||
| SpawnTrip::UsingBike(_, ref goal) => match goal {
|
| SpawnTrip::UsingBike(_, ref goal) => match goal {
|
||||||
DrivingGoal::ParkNear(_) => None,
|
DrivingGoal::ParkNear(_) => None,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
CarID, Command, CreateCar, CreatePedestrian, DrivingGoal, ParkingSimState, ParkingSpot,
|
CarID, Command, CreateCar, CreatePedestrian, DrivingGoal, ParkingSimState, ParkingSpot,
|
||||||
PedestrianID, PersonID, Scheduler, SidewalkPOI, SidewalkSpot, Sim, TripEndpoint, TripLeg,
|
PedestrianID, PersonID, Scheduler, SidewalkPOI, SidewalkSpot, Sim, TripEndpoint, TripLeg,
|
||||||
TripManager, VehicleSpec, VehicleType, MAX_CAR_LENGTH,
|
TripManager, VehicleSpec, VehicleType, BIKE_LENGTH, MAX_CAR_LENGTH,
|
||||||
};
|
};
|
||||||
use abstutil::Timer;
|
use abstutil::Timer;
|
||||||
use geom::{Speed, Time, EPSILON_DIST};
|
use geom::{Speed, Time, EPSILON_DIST};
|
||||||
@ -138,13 +138,15 @@ impl TripSpawner {
|
|||||||
} => {
|
} => {
|
||||||
if start_pos.dist_along() < vehicle_spec.length {
|
if start_pos.dist_along() < vehicle_spec.length {
|
||||||
panic!(
|
panic!(
|
||||||
"Can't spawn a car at {}; too close to the start",
|
"Can't spawn a {:?} at {}; too close to the start",
|
||||||
|
vehicle_spec.vehicle_type,
|
||||||
start_pos.dist_along()
|
start_pos.dist_along()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if start_pos.dist_along() >= map.get_l(start_pos.lane()).length() {
|
if start_pos.dist_along() >= map.get_l(start_pos.lane()).length() {
|
||||||
panic!(
|
panic!(
|
||||||
"Can't spawn a car at {}; {} isn't that long",
|
"Can't spawn a {:?} at {}; {} isn't that long",
|
||||||
|
vehicle_spec.vehicle_type,
|
||||||
start_pos.dist_along(),
|
start_pos.dist_along(),
|
||||||
start_pos.lane()
|
start_pos.lane()
|
||||||
);
|
);
|
||||||
@ -154,7 +156,10 @@ impl TripSpawner {
|
|||||||
if start_pos.lane() == *end_lane
|
if start_pos.lane() == *end_lane
|
||||||
&& start_pos.dist_along() == map.get_l(*end_lane).length()
|
&& start_pos.dist_along() == map.get_l(*end_lane).length()
|
||||||
{
|
{
|
||||||
panic!("Can't start a car at the edge of a border already");
|
panic!(
|
||||||
|
"Can't start a {:?} at the edge of a border already",
|
||||||
|
vehicle_spec.vehicle_type
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DrivingGoal::ParkNear(_) => {}
|
DrivingGoal::ParkNear(_) => {}
|
||||||
@ -534,16 +539,17 @@ impl TripSpawner {
|
|||||||
|
|
||||||
impl TripSpec {
|
impl TripSpec {
|
||||||
// If possible, fixes problems that schedule_trip would hit.
|
// If possible, fixes problems that schedule_trip would hit.
|
||||||
pub fn spawn_car_at(pos: Position, map: &Map) -> Option<Position> {
|
pub fn spawn_vehicle_at(pos: Position, is_bike: bool, map: &Map) -> Option<Position> {
|
||||||
let len = map.get_l(pos.lane()).length();
|
let lane_len = map.get_l(pos.lane()).length();
|
||||||
|
let vehicle_len = if is_bike { BIKE_LENGTH } else { MAX_CAR_LENGTH };
|
||||||
// There's no hope.
|
// There's no hope.
|
||||||
if len <= MAX_CAR_LENGTH {
|
if lane_len <= vehicle_len {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if pos.dist_along() < MAX_CAR_LENGTH {
|
if pos.dist_along() < vehicle_len {
|
||||||
Some(Position::new(pos.lane(), MAX_CAR_LENGTH))
|
Some(Position::new(pos.lane(), vehicle_len))
|
||||||
} else if pos.dist_along() == len {
|
} else if pos.dist_along() == lane_len {
|
||||||
Some(Position::new(pos.lane(), pos.dist_along() - EPSILON_DIST))
|
Some(Position::new(pos.lane(), pos.dist_along() - EPSILON_DIST))
|
||||||
} else {
|
} else {
|
||||||
Some(pos)
|
Some(pos)
|
||||||
|
Loading…
Reference in New Issue
Block a user