mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +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
|
||||
8b949cc34d9a27ace0bd8ecde55a9520 data/system/synthetic_maps/signal_single.json
|
||||
1cd7be125e1d992613ed3a41e8b25b6a data/system/synthetic_maps/signal_fan_in.json
|
||||
dc7d7c8b8dec9c2d0375df3ed0c02d87 data/system/scenarios/ballard/weekday.bin
|
||||
ec3d36603a91a1b61a63823404ad16d6 data/system/scenarios/intl_district/weekday.bin
|
||||
34f366fc48867dc4d923fc638e804af0 data/system/scenarios/23rd/weekday.bin
|
||||
bca018492766b536680a6aae9592d397 data/system/scenarios/downtown/weekday.bin
|
||||
354a0d31dd19b31fe4599233a2057c41 data/system/scenarios/huge_seattle/weekday.bin
|
||||
60712719b44a47cc6accf97d069fac92 data/system/scenarios/caphill/weekday.bin
|
||||
8e38d4e4a93beb7080029dcb76d47563 data/system/scenarios/montlake/weekday.bin
|
||||
ad5d2c7a2c73ef5bf4a09ff11845c166 data/system/prebaked_results/signal_single/tutorial lvl1.bin
|
||||
81081122aa46e8651d8f07bb606bc77a data/system/prebaked_results/signal_single/tutorial lvl2.bin
|
||||
e15dd2d01fccadb1f16c4ed9f732b377 data/system/prebaked_results/montlake/car vs bike contention.bin
|
||||
1f1314220db40c778c18cd03e9af5d18 data/system/prebaked_results/montlake/weekday.bin
|
||||
ba713f7f6ad0c0201f1447d77957ce75 data/system/prebaked_results/montlake/car vs bus contention.bin
|
||||
1d447747aa2e493310abe5e103a1f693 data/system/scenarios/ballard/weekday.bin
|
||||
a72c52c5493d3d7eeaec296ffc7025a2 data/system/scenarios/intl_district/weekday.bin
|
||||
86603a31ee66b91ebb4a66e1146a3b17 data/system/scenarios/23rd/weekday.bin
|
||||
17a1f28e4418937ff17504e357206b8c data/system/scenarios/downtown/weekday.bin
|
||||
afb0ab6073cd6439ccaa41addd3de68b data/system/scenarios/huge_seattle/weekday.bin
|
||||
248f2874b28dfda11cb052e53ef51414 data/system/scenarios/caphill/weekday.bin
|
||||
bf0bef6566fb918db5c9ad3e9054731a data/system/scenarios/montlake/weekday.bin
|
||||
3e4614071e27205513a5cc9b7fc11c90 data/system/prebaked_results/signal_single/tutorial lvl1.bin
|
||||
eb732e116af8c64cd879e9acb1b2eb1f data/system/prebaked_results/signal_single/tutorial lvl2.bin
|
||||
9577e253b4fa810edef68f3dd8860ff0 data/system/prebaked_results/montlake/car vs bike contention.bin
|
||||
de9631bca160dea190cc23e5ac0b7139 data/system/prebaked_results/montlake/weekday.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(),
|
||||
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!(
|
||||
"{} at {}: try to drive from {} to {}",
|
||||
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),
|
||||
driving_goal(goal),
|
||||
),
|
||||
SpawnTrip::FromBorder { i, goal, .. } => (ID::Intersection(*i), driving_goal(goal)),
|
||||
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => {
|
||||
(ID::Building(*start_bldg), driving_goal(goal))
|
||||
}
|
||||
@ -445,6 +454,9 @@ impl DotMap {
|
||||
SpawnTrip::CarAppearing { start, goal, .. } => {
|
||||
(start.pt(map), goal.pt(map))
|
||||
}
|
||||
SpawnTrip::FromBorder { i, goal, .. } => {
|
||||
(map.get_i(*i).polygon.center(), goal.pt(map))
|
||||
}
|
||||
SpawnTrip::MaybeUsingParkedCar(b, goal) => {
|
||||
(map.get_b(*b).polygon.center(), goal.pt(map))
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ fn schedule_trip(
|
||||
};
|
||||
match src {
|
||||
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(
|
||||
sim.random_person(true),
|
||||
sim.time(),
|
||||
|
@ -68,12 +68,18 @@ impl Intersection {
|
||||
.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> {
|
||||
self.outgoing_lanes
|
||||
let mut choices: Vec<LaneID> = self
|
||||
.outgoing_lanes
|
||||
.iter()
|
||||
.filter(|l| constraints.can_use(map.get_l(**l), map))
|
||||
.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 {
|
||||
|
@ -2,10 +2,8 @@ use crate::psrc::{Endpoint, Mode, Parcel, Purpose};
|
||||
use crate::PopDat;
|
||||
use abstutil::{prettyprint_usize, MultiMap, Timer};
|
||||
use geom::{Distance, Duration, LonLat, Polygon, Pt2D, Time};
|
||||
use map_model::{BuildingID, IntersectionID, Map, PathConstraints, Position};
|
||||
use sim::{
|
||||
DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip, TripSpec,
|
||||
};
|
||||
use map_model::{BuildingID, IntersectionID, Map, PathConstraints};
|
||||
use sim::{DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -37,72 +35,45 @@ impl Trip {
|
||||
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 {
|
||||
Mode::Drive => match self.from {
|
||||
TripEndpt::Border(i, _) => {
|
||||
if let Some(start) = TripSpec::spawn_car_at(
|
||||
Position::new(
|
||||
map.get_i(i).get_outgoing_lanes(map, PathConstraints::Car)[0],
|
||||
Distance::ZERO,
|
||||
),
|
||||
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(
|
||||
TripEndpt::Border(i, _) => SpawnTrip::FromBorder {
|
||||
i,
|
||||
goal: self.to.driving_goal(PathConstraints::Car, map),
|
||||
is_bike: false,
|
||||
},
|
||||
TripEndpt::Building(b) => SpawnTrip::MaybeUsingParkedCar(
|
||||
b,
|
||||
self.to.driving_goal(PathConstraints::Car, map),
|
||||
)),
|
||||
),
|
||||
},
|
||||
Mode::Bike => match self.from {
|
||||
TripEndpt::Building(b) => Some(SpawnTrip::UsingBike(
|
||||
TripEndpt::Building(b) => SpawnTrip::UsingBike(
|
||||
SidewalkSpot::building(b, map),
|
||||
self.to.driving_goal(PathConstraints::Bike, map),
|
||||
)),
|
||||
TripEndpt::Border(i, _) => {
|
||||
if let Some(start) = TripSpec::spawn_car_at(
|
||||
Position::new(
|
||||
map.get_i(i).get_outgoing_lanes(map, PathConstraints::Bike)[0],
|
||||
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
|
||||
}
|
||||
}
|
||||
),
|
||||
TripEndpt::Border(i, _) => SpawnTrip::FromBorder {
|
||||
i,
|
||||
goal: self.to.driving_goal(PathConstraints::Bike, map),
|
||||
is_bike: true,
|
||||
},
|
||||
},
|
||||
Mode::Walk => Some(SpawnTrip::JustWalking(
|
||||
Mode::Walk => SpawnTrip::JustWalking(
|
||||
self.from.start_sidewalk_spot(map),
|
||||
self.to.end_sidewalk_spot(map),
|
||||
)),
|
||||
),
|
||||
Mode::Transit => {
|
||||
let start = self.from.start_sidewalk_spot(map);
|
||||
let goal = self.to.end_sidewalk_spot(map);
|
||||
if let Some((stop1, stop2, route)) =
|
||||
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 {
|
||||
//timer.warn(format!("{:?} not actually using transit, because pathfinding
|
||||
// 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)
|
||||
let mut trips_per_person: MultiMap<(usize, usize), ((usize, bool, usize), usize)> =
|
||||
MultiMap::new();
|
||||
for (trip, depart, person, seq) in timer
|
||||
.parallelize("turn PSRC trips into SpawnTrips", trips, |trip| {
|
||||
trip.to_spawn_trip(map)
|
||||
.map(|spawn| (spawn, trip.depart_at, trip.person, trip.seq))
|
||||
for (trip, depart, person, seq) in
|
||||
timer.parallelize("turn PSRC trips into SpawnTrips", trips, |trip| {
|
||||
(
|
||||
trip.to_spawn_trip(map),
|
||||
trip.depart_at,
|
||||
trip.person,
|
||||
trip.seq,
|
||||
)
|
||||
})
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
let idx = individ_trips.len();
|
||||
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;
|
||||
for trip in &trips {
|
||||
match trip.trip {
|
||||
SpawnTrip::CarAppearing { is_bike, .. } => {
|
||||
SpawnTrip::FromBorder { is_bike, .. } => {
|
||||
if !is_bike {
|
||||
has_car = true;
|
||||
}
|
||||
|
@ -1,12 +1,7 @@
|
||||
use crate::{
|
||||
DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip, BIKE_LENGTH,
|
||||
MAX_CAR_LENGTH,
|
||||
};
|
||||
use crate::{DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip};
|
||||
use abstutil::Timer;
|
||||
use geom::{Duration, Time};
|
||||
use map_model::{
|
||||
BuildingID, DirectedRoadID, FullNeighborhoodInfo, LaneID, Map, PathConstraints, Position,
|
||||
};
|
||||
use map_model::{BuildingID, DirectedRoadID, FullNeighborhoodInfo, Map, PathConstraints};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
@ -80,8 +75,24 @@ impl ScenarioGenerator {
|
||||
for s in &self.border_spawn_over_time {
|
||||
timer.next();
|
||||
s.spawn_peds(rng, &mut scenario, &neighborhoods, map, timer);
|
||||
s.spawn_cars(rng, &mut scenario, &neighborhoods, map, timer);
|
||||
s.spawn_bikes(rng, &mut scenario, &neighborhoods, map, timer);
|
||||
s.spawn_vehicles(
|
||||
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));
|
||||
@ -327,97 +338,34 @@ impl BorderSpawnOverTime {
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_cars(
|
||||
fn spawn_vehicles(
|
||||
&self,
|
||||
num: usize,
|
||||
constraints: PathConstraints,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
if self.num_cars == 0 {
|
||||
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 {
|
||||
for _ in 0..num {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
if let Some(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());
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
trips: vec![IndividTrip {
|
||||
depart,
|
||||
trip: SpawnTrip::CarAppearing {
|
||||
// Safe because pick_starting_lanes checks for this
|
||||
start: Position::new(*lanes.choose(rng).unwrap(), MAX_CAR_LENGTH),
|
||||
trip: SpawnTrip::FromBorder {
|
||||
i: self.start_from_border.src_i(map),
|
||||
goal,
|
||||
is_bike: false,
|
||||
is_bike: constraints == PathConstraints::Bike,
|
||||
},
|
||||
}],
|
||||
has_car: true,
|
||||
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,
|
||||
has_car: constraints == PathConstraints::Car,
|
||||
car_initially_parked_at: None,
|
||||
});
|
||||
}
|
||||
@ -487,22 +435,3 @@ fn rand_time(rng: &mut XorShiftRng, low: Time, high: Time) -> Time {
|
||||
assert!(high > low);
|
||||
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 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::Rng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
@ -39,11 +41,16 @@ pub struct IndividTrip {
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum SpawnTrip {
|
||||
// Only for interactive / debug trips
|
||||
CarAppearing {
|
||||
// TODO Replace start with building|border
|
||||
start: Position,
|
||||
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,
|
||||
},
|
||||
MaybeUsingParkedCar(BuildingID, DrivingGoal),
|
||||
@ -90,9 +97,14 @@ impl Scenario {
|
||||
// TODO Or spawner?
|
||||
sim.new_person(p.id, p.has_car);
|
||||
for t in &p.trips {
|
||||
// The RNG call is stable over edits.
|
||||
let spec = t.trip.clone().to_trip_spec(rng);
|
||||
spawner.schedule_trip(p.id, t.depart, spec, map, sim);
|
||||
// The RNG call might change over edits for picking the spawning lane from a border
|
||||
// with multiple choices for a vehicle type.
|
||||
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 {
|
||||
fn to_trip_spec(self, rng: &mut XorShiftRng) -> TripSpec {
|
||||
fn to_trip_spec(self, rng: &mut XorShiftRng, map: &Map) -> Option<TripSpec> {
|
||||
match self {
|
||||
SpawnTrip::CarAppearing {
|
||||
start,
|
||||
goal,
|
||||
is_bike,
|
||||
..
|
||||
} => TripSpec::CarAppearing {
|
||||
} => Some(TripSpec::CarAppearing {
|
||||
start_pos: start,
|
||||
goal,
|
||||
vehicle_spec: if is_bike {
|
||||
@ -310,37 +322,67 @@ impl SpawnTrip {
|
||||
Scenario::rand_car(rng)
|
||||
},
|
||||
ped_speed: Scenario::rand_ped_speed(rng),
|
||||
},
|
||||
SpawnTrip::MaybeUsingParkedCar(start_bldg, goal) => TripSpec::MaybeUsingParkedCar {
|
||||
start_bldg,
|
||||
}),
|
||||
SpawnTrip::FromBorder {
|
||||
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,
|
||||
vehicle_spec: if is_bike {
|
||||
Scenario::rand_bike(rng)
|
||||
} else {
|
||||
Scenario::rand_car(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,
|
||||
goal,
|
||||
vehicle: Scenario::rand_bike(rng),
|
||||
ped_speed: Scenario::rand_ped_speed(rng),
|
||||
},
|
||||
SpawnTrip::JustWalking(start, goal) => TripSpec::JustWalking {
|
||||
}),
|
||||
SpawnTrip::JustWalking(start, goal) => Some(TripSpec::JustWalking {
|
||||
start,
|
||||
goal,
|
||||
ped_speed: Scenario::rand_ped_speed(rng),
|
||||
},
|
||||
SpawnTrip::UsingTransit(start, goal, route, stop1, stop2) => TripSpec::UsingTransit {
|
||||
start,
|
||||
goal,
|
||||
route,
|
||||
stop1,
|
||||
stop2,
|
||||
ped_speed: Scenario::rand_ped_speed(rng),
|
||||
},
|
||||
}),
|
||||
SpawnTrip::UsingTransit(start, goal, route, stop1, stop2) => {
|
||||
Some(TripSpec::UsingTransit {
|
||||
start,
|
||||
goal,
|
||||
route,
|
||||
stop1,
|
||||
stop2,
|
||||
ped_speed: Scenario::rand_ped_speed(rng),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_from_bldg(&self) -> Option<BuildingID> {
|
||||
match self {
|
||||
SpawnTrip::CarAppearing { .. } => None,
|
||||
SpawnTrip::FromBorder { .. } => None,
|
||||
SpawnTrip::MaybeUsingParkedCar(b, _) => Some(*b),
|
||||
SpawnTrip::UsingBike(ref spot, _)
|
||||
| SpawnTrip::JustWalking(ref spot, _)
|
||||
@ -353,8 +395,8 @@ impl SpawnTrip {
|
||||
|
||||
pub fn start_from_border(&self) -> Option<IntersectionID> {
|
||||
match self {
|
||||
// TODO CarAppearing might be from a border
|
||||
SpawnTrip::CarAppearing { .. } => None,
|
||||
SpawnTrip::FromBorder { i, .. } => Some(*i),
|
||||
SpawnTrip::MaybeUsingParkedCar(_, _) => None,
|
||||
SpawnTrip::UsingBike(ref spot, _)
|
||||
| SpawnTrip::JustWalking(ref spot, _)
|
||||
@ -368,6 +410,7 @@ impl SpawnTrip {
|
||||
pub fn end_at_bldg(&self) -> Option<BuildingID> {
|
||||
match self {
|
||||
SpawnTrip::CarAppearing { ref goal, .. }
|
||||
| SpawnTrip::FromBorder { ref goal, .. }
|
||||
| SpawnTrip::MaybeUsingParkedCar(_, ref goal)
|
||||
| SpawnTrip::UsingBike(_, ref goal) => match goal {
|
||||
DrivingGoal::ParkNear(b) => Some(*b),
|
||||
@ -385,6 +428,7 @@ impl SpawnTrip {
|
||||
pub fn end_at_border(&self) -> Option<IntersectionID> {
|
||||
match self {
|
||||
SpawnTrip::CarAppearing { ref goal, .. }
|
||||
| SpawnTrip::FromBorder { ref goal, .. }
|
||||
| SpawnTrip::MaybeUsingParkedCar(_, ref goal)
|
||||
| SpawnTrip::UsingBike(_, ref goal) => match goal {
|
||||
DrivingGoal::ParkNear(_) => None,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
CarID, Command, CreateCar, CreatePedestrian, DrivingGoal, ParkingSimState, ParkingSpot,
|
||||
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 geom::{Speed, Time, EPSILON_DIST};
|
||||
@ -138,13 +138,15 @@ impl TripSpawner {
|
||||
} => {
|
||||
if start_pos.dist_along() < vehicle_spec.length {
|
||||
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()
|
||||
);
|
||||
}
|
||||
if start_pos.dist_along() >= map.get_l(start_pos.lane()).length() {
|
||||
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.lane()
|
||||
);
|
||||
@ -154,7 +156,10 @@ impl TripSpawner {
|
||||
if start_pos.lane() == *end_lane
|
||||
&& 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(_) => {}
|
||||
@ -534,16 +539,17 @@ impl TripSpawner {
|
||||
|
||||
impl TripSpec {
|
||||
// If possible, fixes problems that schedule_trip would hit.
|
||||
pub fn spawn_car_at(pos: Position, map: &Map) -> Option<Position> {
|
||||
let len = map.get_l(pos.lane()).length();
|
||||
pub fn spawn_vehicle_at(pos: Position, is_bike: bool, map: &Map) -> Option<Position> {
|
||||
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.
|
||||
if len <= MAX_CAR_LENGTH {
|
||||
if lane_len <= vehicle_len {
|
||||
return None;
|
||||
}
|
||||
|
||||
if pos.dist_along() < MAX_CAR_LENGTH {
|
||||
Some(Position::new(pos.lane(), MAX_CAR_LENGTH))
|
||||
} else if pos.dist_along() == len {
|
||||
if pos.dist_along() < vehicle_len {
|
||||
Some(Position::new(pos.lane(), vehicle_len))
|
||||
} else if pos.dist_along() == lane_len {
|
||||
Some(Position::new(pos.lane(), pos.dist_along() - EPSILON_DIST))
|
||||
} else {
|
||||
Some(pos)
|
||||
|
Loading…
Reference in New Issue
Block a user