mirror of
https://github.com/a-b-street/abstreet.git
synced 2025-01-08 15:55:12 +03:00
organizing scenario code a little
This commit is contained in:
parent
8ab4b403fa
commit
37ce6ff357
@ -94,6 +94,7 @@ impl Scenario {
|
|||||||
|
|
||||||
// Don't let two pedestrians starting from one building use the same car.
|
// Don't let two pedestrians starting from one building use the same car.
|
||||||
let mut reserved_cars: HashSet<CarID> = HashSet::new();
|
let mut reserved_cars: HashSet<CarID> = HashSet::new();
|
||||||
|
|
||||||
for s in &self.spawn_over_time {
|
for s in &self.spawn_over_time {
|
||||||
if !neighborhoods.contains_key(&s.start_from_neighborhood) {
|
if !neighborhoods.contains_key(&s.start_from_neighborhood) {
|
||||||
panic!("Neighborhood {} isn't defined", s.start_from_neighborhood);
|
panic!("Neighborhood {} isn't defined", s.start_from_neighborhood);
|
||||||
@ -102,199 +103,16 @@ impl Scenario {
|
|||||||
timer.start_iter("SpawnOverTime each agent", s.num_agents);
|
timer.start_iter("SpawnOverTime each agent", s.num_agents);
|
||||||
for _ in 0..s.num_agents {
|
for _ in 0..s.num_agents {
|
||||||
timer.next();
|
timer.next();
|
||||||
let spawn_time = rand_time(rng, s.start_time, s.stop_time);
|
s.spawn_agent(rng, sim, &mut reserved_cars, &neighborhoods, map, timer);
|
||||||
// Note that it's fine for agents to start/end at the same building. Later we might
|
|
||||||
// want a better assignment of people per household, or workers per office building.
|
|
||||||
let from_bldg = *neighborhoods[&s.start_from_neighborhood]
|
|
||||||
.buildings
|
|
||||||
.choose(rng)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// What mode?
|
|
||||||
if let Some(parked_car) = sim
|
|
||||||
.get_parked_cars_by_owner(from_bldg)
|
|
||||||
.into_iter()
|
|
||||||
.find(|p| !reserved_cars.contains(&p.vehicle.id))
|
|
||||||
{
|
|
||||||
if let Some(goal) = s.goal.pick_driving_goal(map, &neighborhoods, rng, timer) {
|
|
||||||
reserved_cars.insert(parked_car.vehicle.id);
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::UsingParkedCar(
|
|
||||||
SidewalkSpot::building(from_bldg, map),
|
|
||||||
parked_car.spot,
|
|
||||||
goal,
|
|
||||||
),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if rng.gen_bool(s.percent_biking) {
|
|
||||||
if let Some(goal) = s.goal.pick_biking_goal(map, &neighborhoods, rng, timer) {
|
|
||||||
let start_at = map.get_b(from_bldg).sidewalk();
|
|
||||||
// TODO Just start biking on the other side of the street if the sidewalk
|
|
||||||
// is on a one-way. Or at least warn.
|
|
||||||
if map
|
|
||||||
.get_parent(start_at)
|
|
||||||
.sidewalk_to_bike(start_at)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
let ok = if let DrivingGoal::ParkNear(to_bldg) = goal {
|
|
||||||
let end_at = map.get_b(to_bldg).sidewalk();
|
|
||||||
map.get_parent(end_at).sidewalk_to_bike(end_at).is_some()
|
|
||||||
&& start_at != end_at
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
if ok {
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::UsingBike(
|
|
||||||
SidewalkSpot::building(from_bldg, map),
|
|
||||||
rand_bike(rng),
|
|
||||||
goal,
|
|
||||||
),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let Some(goal) = s.goal.pick_walking_goal(map, &neighborhoods, rng, timer)
|
|
||||||
{
|
|
||||||
let start_spot = SidewalkSpot::building(from_bldg, map);
|
|
||||||
|
|
||||||
if rng.gen_bool(s.percent_use_transit) {
|
|
||||||
// TODO This throws away some work. It also sequentially does expensive
|
|
||||||
// work right here.
|
|
||||||
if let Some((stop1, stop2, route)) = Pathfinder::should_use_transit(
|
|
||||||
map,
|
|
||||||
start_spot.sidewalk_pos,
|
|
||||||
goal.sidewalk_pos,
|
|
||||||
) {
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::UsingTransit(start_spot, route, stop1, stop2, goal),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sim.schedule_trip(spawn_time, TripSpec::JustWalking(start_spot, goal), map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.start_iter("BorderSpawnOverTime", self.border_spawn_over_time.len());
|
timer.start_iter("BorderSpawnOverTime", self.border_spawn_over_time.len());
|
||||||
for s in &self.border_spawn_over_time {
|
for s in &self.border_spawn_over_time {
|
||||||
timer.next();
|
timer.next();
|
||||||
if let Some(start) = SidewalkSpot::start_at_border(s.start_from_border, map) {
|
s.spawn_peds(rng, sim, &neighborhoods, map, timer);
|
||||||
for _ in 0..s.num_peds {
|
s.spawn_cars(rng, sim, &neighborhoods, map, timer);
|
||||||
let spawn_time = rand_time(rng, s.start_time, s.stop_time);
|
s.spawn_bikes(rng, sim, &neighborhoods, map, timer);
|
||||||
if let Some(goal) = s.goal.pick_walking_goal(map, &neighborhoods, rng, timer) {
|
|
||||||
if rng.gen_bool(s.percent_use_transit) {
|
|
||||||
// TODO This throws away some work. It also sequentially does expensive
|
|
||||||
// work right here.
|
|
||||||
if let Some((stop1, stop2, route)) = Pathfinder::should_use_transit(
|
|
||||||
map,
|
|
||||||
start.sidewalk_pos,
|
|
||||||
goal.sidewalk_pos,
|
|
||||||
) {
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::UsingTransit(
|
|
||||||
start.clone(),
|
|
||||||
route,
|
|
||||||
stop1,
|
|
||||||
stop2,
|
|
||||||
goal,
|
|
||||||
),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::JustWalking(start.clone(), goal),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if s.num_peds > 0 {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Can't start_at_border for {} without sidewalk",
|
|
||||||
s.start_from_border
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let starting_driving_lanes = map
|
|
||||||
.get_i(s.start_from_border)
|
|
||||||
.get_outgoing_lanes(map, LaneType::Driving);
|
|
||||||
if !starting_driving_lanes.is_empty() {
|
|
||||||
let lane_len = map.get_l(starting_driving_lanes[0]).length();
|
|
||||||
if lane_len < MAX_CAR_LENGTH {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Skipping {:?} because {} is only {}, too short to spawn cars",
|
|
||||||
s, starting_driving_lanes[0], lane_len
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
for _ in 0..s.num_cars {
|
|
||||||
let spawn_time = rand_time(rng, s.start_time, s.stop_time);
|
|
||||||
if let Some(goal) =
|
|
||||||
s.goal.pick_driving_goal(map, &neighborhoods, rng, timer)
|
|
||||||
{
|
|
||||||
let vehicle = rand_car(rng);
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::CarAppearing(
|
|
||||||
// TODO could pretty easily pick any lane here
|
|
||||||
Position::new(starting_driving_lanes[0], vehicle.length),
|
|
||||||
vehicle,
|
|
||||||
goal,
|
|
||||||
),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if s.num_cars > 0 {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Can't start car at border for {}",
|
|
||||||
s.start_from_border
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut starting_biking_lanes = map
|
|
||||||
.get_i(s.start_from_border)
|
|
||||||
.get_outgoing_lanes(map, LaneType::Biking);
|
|
||||||
for l in starting_driving_lanes {
|
|
||||||
if map.get_parent(l).supports_bikes() {
|
|
||||||
starting_biking_lanes.push(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !starting_biking_lanes.is_empty() {
|
|
||||||
for _ in 0..s.num_bikes {
|
|
||||||
let spawn_time = rand_time(rng, s.start_time, s.stop_time);
|
|
||||||
if let Some(goal) = s.goal.pick_biking_goal(map, &neighborhoods, rng, timer) {
|
|
||||||
let bike = rand_bike(rng);
|
|
||||||
sim.schedule_trip(
|
|
||||||
spawn_time,
|
|
||||||
TripSpec::CarAppearing(
|
|
||||||
Position::new(starting_biking_lanes[0], bike.length),
|
|
||||||
bike,
|
|
||||||
goal,
|
|
||||||
),
|
|
||||||
map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if s.num_bikes > 0 {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Can't start bike at border for {}",
|
|
||||||
s.start_from_border
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sim.spawn_all_trips(map, timer);
|
sim.spawn_all_trips(map, timer);
|
||||||
@ -356,6 +174,270 @@ impl Scenario {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SpawnOverTime {
|
||||||
|
fn spawn_agent(
|
||||||
|
&self,
|
||||||
|
rng: &mut XorShiftRng,
|
||||||
|
sim: &mut Sim,
|
||||||
|
reserved_cars: &mut HashSet<CarID>,
|
||||||
|
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||||
|
map: &Map,
|
||||||
|
timer: &mut Timer,
|
||||||
|
) {
|
||||||
|
let spawn_time = rand_time(rng, self.start_time, self.stop_time);
|
||||||
|
// Note that it's fine for agents to start/end at the same building. Later we might
|
||||||
|
// want a better assignment of people per household, or workers per office building.
|
||||||
|
let from_bldg = *neighborhoods[&self.start_from_neighborhood]
|
||||||
|
.buildings
|
||||||
|
.choose(rng)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// What mode?
|
||||||
|
if let Some(parked_car) = sim
|
||||||
|
.get_parked_cars_by_owner(from_bldg)
|
||||||
|
.into_iter()
|
||||||
|
.find(|p| !reserved_cars.contains(&p.vehicle.id))
|
||||||
|
{
|
||||||
|
if let Some(goal) = self.goal.pick_driving_goal(
|
||||||
|
vec![LaneType::Driving],
|
||||||
|
map,
|
||||||
|
&neighborhoods,
|
||||||
|
rng,
|
||||||
|
timer,
|
||||||
|
) {
|
||||||
|
reserved_cars.insert(parked_car.vehicle.id);
|
||||||
|
sim.schedule_trip(
|
||||||
|
spawn_time,
|
||||||
|
TripSpec::UsingParkedCar(
|
||||||
|
SidewalkSpot::building(from_bldg, map),
|
||||||
|
parked_car.spot,
|
||||||
|
goal,
|
||||||
|
),
|
||||||
|
map,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rng.gen_bool(self.percent_biking) {
|
||||||
|
if let Some(goal) = self.goal.pick_driving_goal(
|
||||||
|
vec![LaneType::Driving, LaneType::Biking],
|
||||||
|
map,
|
||||||
|
&neighborhoods,
|
||||||
|
rng,
|
||||||
|
timer,
|
||||||
|
) {
|
||||||
|
let start_at = map.get_b(from_bldg).sidewalk();
|
||||||
|
// TODO Just start biking on the other side of the street if the sidewalk
|
||||||
|
// is on a one-way. Or at least warn.
|
||||||
|
if map
|
||||||
|
.get_parent(start_at)
|
||||||
|
.sidewalk_to_bike(start_at)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let ok = if let DrivingGoal::ParkNear(to_bldg) = goal {
|
||||||
|
let end_at = map.get_b(to_bldg).sidewalk();
|
||||||
|
map.get_parent(end_at).sidewalk_to_bike(end_at).is_some()
|
||||||
|
&& start_at != end_at
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
if ok {
|
||||||
|
sim.schedule_trip(
|
||||||
|
spawn_time,
|
||||||
|
TripSpec::UsingBike(
|
||||||
|
SidewalkSpot::building(from_bldg, map),
|
||||||
|
rand_bike(rng),
|
||||||
|
goal,
|
||||||
|
),
|
||||||
|
map,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(goal) = self.goal.pick_walking_goal(map, &neighborhoods, rng, timer) {
|
||||||
|
let start_spot = SidewalkSpot::building(from_bldg, map);
|
||||||
|
|
||||||
|
if rng.gen_bool(self.percent_use_transit) {
|
||||||
|
// TODO This throws away some work. It also sequentially does expensive
|
||||||
|
// work right here.
|
||||||
|
if let Some((stop1, stop2, route)) =
|
||||||
|
Pathfinder::should_use_transit(map, start_spot.sidewalk_pos, goal.sidewalk_pos)
|
||||||
|
{
|
||||||
|
sim.schedule_trip(
|
||||||
|
spawn_time,
|
||||||
|
TripSpec::UsingTransit(start_spot, route, stop1, stop2, goal),
|
||||||
|
map,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sim.schedule_trip(spawn_time, TripSpec::JustWalking(start_spot, goal), map);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.warn(format!("Couldn't fulfill {:?} at all", self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BorderSpawnOverTime {
|
||||||
|
fn spawn_peds(
|
||||||
|
&self,
|
||||||
|
rng: &mut XorShiftRng,
|
||||||
|
sim: &mut Sim,
|
||||||
|
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||||
|
map: &Map,
|
||||||
|
timer: &mut Timer,
|
||||||
|
) {
|
||||||
|
if self.num_peds == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = if let Some(s) = SidewalkSpot::start_at_border(self.start_from_border, map) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
timer.warn(format!(
|
||||||
|
"Can't start_at_border for {} without sidewalk",
|
||||||
|
self.start_from_border
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
for _ in 0..self.num_peds {
|
||||||
|
let spawn_time = rand_time(rng, self.start_time, self.stop_time);
|
||||||
|
if let Some(goal) = self.goal.pick_walking_goal(map, &neighborhoods, rng, timer) {
|
||||||
|
if rng.gen_bool(self.percent_use_transit) {
|
||||||
|
// TODO This throws away some work. It also sequentially does expensive
|
||||||
|
// work right here.
|
||||||
|
if let Some((stop1, stop2, route)) =
|
||||||
|
Pathfinder::should_use_transit(map, start.sidewalk_pos, goal.sidewalk_pos)
|
||||||
|
{
|
||||||
|
sim.schedule_trip(
|
||||||
|
spawn_time,
|
||||||
|
TripSpec::UsingTransit(start.clone(), route, stop1, stop2, goal),
|
||||||
|
map,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sim.schedule_trip(spawn_time, TripSpec::JustWalking(start.clone(), goal), map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_cars(
|
||||||
|
&self,
|
||||||
|
rng: &mut XorShiftRng,
|
||||||
|
sim: &mut Sim,
|
||||||
|
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||||
|
map: &Map,
|
||||||
|
timer: &mut Timer,
|
||||||
|
) {
|
||||||
|
if self.num_cars == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let starting_driving_lanes = map
|
||||||
|
.get_i(self.start_from_border)
|
||||||
|
.get_outgoing_lanes(map, LaneType::Driving);
|
||||||
|
if starting_driving_lanes.is_empty() {
|
||||||
|
timer.warn(format!(
|
||||||
|
"Can't start car at border for {}",
|
||||||
|
self.start_from_border
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lane_len = map.get_l(starting_driving_lanes[0]).length();
|
||||||
|
if lane_len < MAX_CAR_LENGTH {
|
||||||
|
timer.warn(format!(
|
||||||
|
"Skipping {:?} because {} is only {}, too short to spawn cars",
|
||||||
|
self, starting_driving_lanes[0], lane_len
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for _ in 0..self.num_cars {
|
||||||
|
let spawn_time = rand_time(rng, self.start_time, self.stop_time);
|
||||||
|
if let Some(goal) = self.goal.pick_driving_goal(
|
||||||
|
vec![LaneType::Driving],
|
||||||
|
map,
|
||||||
|
&neighborhoods,
|
||||||
|
rng,
|
||||||
|
timer,
|
||||||
|
) {
|
||||||
|
let vehicle = rand_car(rng);
|
||||||
|
sim.schedule_trip(
|
||||||
|
spawn_time,
|
||||||
|
TripSpec::CarAppearing(
|
||||||
|
// TODO could pretty easily pick any lane here
|
||||||
|
Position::new(starting_driving_lanes[0], vehicle.length),
|
||||||
|
vehicle,
|
||||||
|
goal,
|
||||||
|
),
|
||||||
|
map,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_bikes(
|
||||||
|
&self,
|
||||||
|
rng: &mut XorShiftRng,
|
||||||
|
sim: &mut Sim,
|
||||||
|
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||||
|
map: &Map,
|
||||||
|
timer: &mut Timer,
|
||||||
|
) {
|
||||||
|
if self.num_bikes == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut starting_biking_lanes = map
|
||||||
|
.get_i(self.start_from_border)
|
||||||
|
.get_outgoing_lanes(map, LaneType::Biking);
|
||||||
|
for l in map
|
||||||
|
.get_i(self.start_from_border)
|
||||||
|
.get_outgoing_lanes(map, LaneType::Driving)
|
||||||
|
{
|
||||||
|
if map.get_parent(l).supports_bikes() {
|
||||||
|
starting_biking_lanes.push(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if starting_biking_lanes.is_empty() {
|
||||||
|
timer.warn(format!(
|
||||||
|
"Can't start bike at border for {}",
|
||||||
|
self.start_from_border
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..self.num_bikes {
|
||||||
|
let spawn_time = rand_time(rng, self.start_time, self.stop_time);
|
||||||
|
if let Some(goal) = self.goal.pick_driving_goal(
|
||||||
|
vec![LaneType::Driving, LaneType::Biking],
|
||||||
|
map,
|
||||||
|
&neighborhoods,
|
||||||
|
rng,
|
||||||
|
timer,
|
||||||
|
) {
|
||||||
|
let bike = rand_bike(rng);
|
||||||
|
sim.schedule_trip(
|
||||||
|
spawn_time,
|
||||||
|
TripSpec::CarAppearing(
|
||||||
|
Position::new(starting_biking_lanes[0], bike.length),
|
||||||
|
bike,
|
||||||
|
goal,
|
||||||
|
),
|
||||||
|
map,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
pub enum OriginDestination {
|
pub enum OriginDestination {
|
||||||
Neighborhood(String),
|
Neighborhood(String),
|
||||||
@ -366,6 +448,7 @@ pub enum OriginDestination {
|
|||||||
impl OriginDestination {
|
impl OriginDestination {
|
||||||
fn pick_driving_goal(
|
fn pick_driving_goal(
|
||||||
&self,
|
&self,
|
||||||
|
lane_types: Vec<LaneType>,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||||
rng: &mut XorShiftRng,
|
rng: &mut XorShiftRng,
|
||||||
@ -376,10 +459,13 @@ impl OriginDestination {
|
|||||||
*neighborhoods[n].buildings.choose(rng).unwrap(),
|
*neighborhoods[n].buildings.choose(rng).unwrap(),
|
||||||
)),
|
)),
|
||||||
OriginDestination::Border(i) => {
|
OriginDestination::Border(i) => {
|
||||||
let lanes = map.get_i(*i).get_incoming_lanes(map, LaneType::Driving);
|
let mut lanes = Vec::new();
|
||||||
|
for lt in lane_types {
|
||||||
|
lanes.extend(map.get_i(*i).get_incoming_lanes(map, lt));
|
||||||
|
}
|
||||||
if lanes.is_empty() {
|
if lanes.is_empty() {
|
||||||
timer.warn(format!(
|
timer.warn(format!(
|
||||||
"Can't spawn a car ending at border {}; no driving lane there",
|
"Can't spawn a car ending at border {}; no appropriate lanes there",
|
||||||
i
|
i
|
||||||
));
|
));
|
||||||
None
|
None
|
||||||
@ -391,34 +477,6 @@ impl OriginDestination {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO nearly a copy of pick_driving_goal! Ew
|
|
||||||
fn pick_biking_goal(
|
|
||||||
&self,
|
|
||||||
map: &Map,
|
|
||||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
|
||||||
rng: &mut XorShiftRng,
|
|
||||||
timer: &mut Timer,
|
|
||||||
) -> Option<DrivingGoal> {
|
|
||||||
match self {
|
|
||||||
OriginDestination::Neighborhood(ref n) => Some(DrivingGoal::ParkNear(
|
|
||||||
*neighborhoods[n].buildings.choose(rng).unwrap(),
|
|
||||||
)),
|
|
||||||
OriginDestination::Border(i) => {
|
|
||||||
let mut lanes = map.get_i(*i).get_incoming_lanes(map, LaneType::Biking);
|
|
||||||
lanes.extend(map.get_i(*i).get_incoming_lanes(map, LaneType::Driving));
|
|
||||||
if lanes.is_empty() {
|
|
||||||
timer.warn(format!(
|
|
||||||
"Can't spawn a bike ending at border {}; no biking or driving lane there",
|
|
||||||
i
|
|
||||||
));
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(DrivingGoal::Border(*i, lanes[0]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pick_walking_goal(
|
fn pick_walking_goal(
|
||||||
&self,
|
&self,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
|
Loading…
Reference in New Issue
Block a user