bring in parking code and some structures needed for it. dont use it yet. switch to Vehicle.

This commit is contained in:
Dustin Carlino 2019-02-22 10:55:13 -08:00
parent ff8ddc94b5
commit 6673807422
7 changed files with 357 additions and 76 deletions

View File

@ -197,9 +197,12 @@ fn spawn_car(
let spawn_time = Duration::seconds(0.2) * (id % 5) as f64;
sim.spawn_car(
CarID::tmp_new(id, VehicleType::Car),
vehicle_len,
new_des_model::Vehicle {
id: CarID::tmp_new(id, VehicleType::Car),
vehicle_type: VehicleType::Car,
length: vehicle_len,
max_speed,
},
path,
spawn_time,
start_dist,

View File

@ -1,20 +1,19 @@
use geom::{Distance, Duration, PolyLine, Speed};
use crate::plugins::sim::new_des_model::Vehicle;
use geom::{Distance, Duration, PolyLine};
use map_model::{Map, Traversable};
use sim::{CarID, DrawCarInput};
use sim::DrawCarInput;
use std::collections::VecDeque;
#[derive(Debug)]
pub struct Car {
pub id: CarID,
pub vehicle_len: Distance,
pub max_speed: Option<Speed>,
pub vehicle: Vehicle,
// Front is always the current step
pub path: VecDeque<Traversable>,
pub end_dist: Distance,
pub state: CarState,
// In reverse order -- most recently left is first. The sum length of these must be >=
// vehicle_len.
// vehicle.length.
pub last_steps: VecDeque<Traversable>,
}
@ -36,7 +35,7 @@ impl Car {
);
let mut speed = on.speed_limit(map);
if let Some(s) = self.max_speed {
if let Some(s) = self.vehicle.max_speed {
speed = speed.min(s);
}
let dt = (dist_int.end - dist_int.start) / speed;
@ -49,7 +48,7 @@ impl Car {
for on in self.last_steps.drain(..) {
len += on.length(map);
keep.push_back(on);
if len >= self.vehicle_len {
if len >= self.vehicle.length {
break;
}
}
@ -58,9 +57,9 @@ impl Car {
pub fn get_draw_car(&self, front: Distance, map: &Map) -> DrawCarInput {
assert!(front >= Distance::ZERO);
let body = if front >= self.vehicle_len {
let body = if front >= self.vehicle.length {
self.path[0]
.slice(front - self.vehicle_len, front, map)
.slice(front - self.vehicle.length, front, map)
.unwrap()
.0
} else {
@ -69,11 +68,11 @@ impl Car {
.slice(Distance::ZERO, front, map)
.map(|(pl, _)| pl.points().clone())
.unwrap_or_else(Vec::new);
let mut leftover = self.vehicle_len - front;
let mut leftover = self.vehicle.length - front;
let mut i = 0;
while leftover > Distance::ZERO {
if i == self.last_steps.len() {
panic!("{} spawned too close to short stuff", self.id);
panic!("{} spawned too close to short stuff", self.vehicle.id);
}
let len = self.last_steps[i].length(map);
let start = (len - leftover).max(Distance::ZERO);
@ -90,7 +89,7 @@ impl Car {
};
DrawCarInput {
id: self.id,
id: self.vehicle.id,
waiting_for_turn: None,
stopping_trace: None,
state: match self.state {
@ -98,7 +97,7 @@ impl Car {
CarState::Queued => sim::CarState::Stuck,
CarState::Crossing(_, _) => sim::CarState::Moving,
},
vehicle_type: self.id.tmp_get_vehicle_type(),
vehicle_type: self.vehicle.vehicle_type,
on: self.path[0],
body,
}

View File

@ -1,10 +1,10 @@
use crate::plugins::sim::new_des_model::{
Car, CarState, IntersectionController, Queue, FOLLOWING_DISTANCE, MAX_VEHICLE_LENGTH,
Car, CarState, IntersectionController, Queue, Vehicle, FOLLOWING_DISTANCE, MAX_VEHICLE_LENGTH,
};
use ezgui::{Color, GfxCtx};
use geom::{Distance, Duration, Speed};
use geom::{Distance, Duration};
use map_model::{IntersectionID, Map, Traversable, LANE_THICKNESS};
use sim::{CarID, DrawCarInput};
use sim::DrawCarInput;
use std::collections::{BTreeMap, VecDeque};
const FREEFLOW: Color = Color::CYAN;
@ -14,15 +14,7 @@ pub struct DrivingSimState {
queues: BTreeMap<Traversable, Queue>,
intersections: BTreeMap<IntersectionID, IntersectionController>,
spawn_later: Vec<(
CarID,
Distance,
Option<Speed>,
Vec<Traversable>,
Duration,
Distance,
Distance,
)>,
spawn_later: Vec<(Vehicle, Vec<Traversable>, Duration, Distance, Distance)>,
}
impl DrivingSimState {
@ -136,16 +128,14 @@ impl DrivingSimState {
pub fn spawn_car(
&mut self,
id: CarID,
vehicle_len: Distance,
max_speed: Option<Speed>,
vehicle: Vehicle,
path: Vec<Traversable>,
start_time: Duration,
start_dist: Distance,
end_dist: Distance,
map: &Map,
) {
if start_dist < vehicle_len {
if start_dist < vehicle.length {
panic!(
"Can't spawn a car at {}; too close to the start",
start_dist
@ -171,15 +161,8 @@ impl DrivingSimState {
);
}
self.spawn_later.push((
id,
vehicle_len,
max_speed,
path,
start_time,
start_dist,
end_dist,
));
self.spawn_later
.push((vehicle, path, start_time, start_dist, end_dist));
}
pub fn step_if_needed(&mut self, time: Duration, map: &Map) {
@ -219,7 +202,7 @@ impl DrivingSimState {
// Carry out the transitions.
for from in head_cars_ready_to_advance {
let car_id = self.queues[&from].cars[0].id;
let car_id = self.queues[&from].cars[0].vehicle.id;
let goto = self.queues[&from].cars[0].path[1];
// Always need to do this check.
@ -254,7 +237,7 @@ impl DrivingSimState {
CarState::Queued => {
follower.state = follower.crossing_state(
// Since the follower was Queued, this must be where they are
from.length(map) - car.vehicle_len - FOLLOWING_DISTANCE,
from.length(map) - car.vehicle.length - FOLLOWING_DISTANCE,
time,
from,
map,
@ -271,13 +254,13 @@ impl DrivingSimState {
car.state = car.crossing_state(Distance::ZERO, time, goto, map);
if goto.maybe_lane().is_some() {
// TODO Actually, don't call turn_finished until the car is at least vehicle_len +
// FOLLOWING_DISTANCE into the next lane. This'll be hard to predict when we're
// TODO Actually, don't call turn_finished until the car is at least vehicle.length
// + FOLLOWING_DISTANCE into the next lane. This'll be hard to predict when we're
// event-based, so hold off on this bit of realism.
self.intersections
.get_mut(&last_step.as_turn().parent)
.unwrap()
.turn_finished(car.id, last_step.as_turn());
.turn_finished(car.vehicle.id, last_step.as_turn());
}
self.queues.get_mut(&goto).unwrap().cars.push_back(car);
@ -285,9 +268,7 @@ impl DrivingSimState {
// Spawn cars at the end, so we can see the correct state of everything else at this time.
let mut retain_spawn = Vec::new();
for (id, vehicle_len, max_speed, path, start_time, start_dist, end_dist) in
self.spawn_later.drain(..)
{
for (vehicle, path, start_time, start_dist, end_dist) in self.spawn_later.drain(..) {
let mut spawned = false;
let first_lane = path[0].as_lane();
@ -296,12 +277,10 @@ impl DrivingSimState {
.nobody_headed_towards(first_lane)
{
if let Some(idx) = self.queues[&Traversable::Lane(first_lane)]
.get_idx_to_insert_car(start_dist, vehicle_len, time)
.get_idx_to_insert_car(start_dist, vehicle.length, time)
{
let mut car = Car {
id,
vehicle_len,
max_speed,
vehicle: vehicle.clone(),
path: VecDeque::from(path.clone()),
end_dist,
state: CarState::Queued,
@ -315,19 +294,11 @@ impl DrivingSimState {
.cars
.insert(idx, car);
spawned = true;
//println!("{} spawned at {}", id, time);
//println!("{} spawned at {}", vehicle.id, time);
}
}
if !spawned {
retain_spawn.push((
id,
vehicle_len,
max_speed,
path,
start_time,
start_dist,
end_dist,
));
retain_spawn.push((vehicle, path, start_time, start_dist, end_dist));
}
}
self.spawn_later = retain_spawn;

View File

@ -1,14 +1,64 @@
mod car;
mod driving;
mod intersection;
mod parking;
mod queue;
pub use self::car::{Car, CarState};
pub use self::driving::DrivingSimState;
pub use self::intersection::IntersectionController;
pub use self::queue::Queue;
use geom::Distance;
use geom::{Distance, Speed};
use map_model::{BuildingID, LaneID};
use serde_derive::{Deserialize, Serialize};
use sim::{CarID, VehicleType};
pub const MIN_VEHICLE_LENGTH: Distance = Distance::const_meters(2.0);
pub const MAX_VEHICLE_LENGTH: Distance = Distance::const_meters(7.0);
pub const FOLLOWING_DISTANCE: Distance = Distance::const_meters(1.0);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Vehicle {
pub id: CarID,
pub vehicle_type: VehicleType,
pub length: Distance,
pub max_speed: Option<Speed>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ParkingSpot {
pub lane: LaneID,
pub idx: usize,
}
impl ParkingSpot {
pub fn new(lane: LaneID, idx: usize) -> ParkingSpot {
ParkingSpot { lane, idx }
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ParkedCar {
pub car: CarID,
pub spot: ParkingSpot,
pub vehicle: Vehicle,
pub owner: Option<BuildingID>,
}
impl ParkedCar {
pub fn new(
car: CarID,
spot: ParkingSpot,
vehicle: Vehicle,
owner: Option<BuildingID>,
) -> ParkedCar {
assert_eq!(vehicle.vehicle_type, VehicleType::Car);
ParkedCar {
car,
spot,
vehicle,
owner,
}
}
}

View File

@ -0,0 +1,258 @@
use crate::plugins::sim::new_des_model::{ParkedCar, ParkingSpot, Vehicle};
use abstutil::{deserialize_btreemap, serialize_btreemap};
use geom::{Angle, Distance, Pt2D};
use map_model;
use map_model::{BuildingID, Lane, LaneID, LaneType, Map, Position, Traversable};
use serde_derive::{Deserialize, Serialize};
use sim::{CarID, CarState, DrawCarInput, VehicleType};
use std::collections::{BTreeMap, HashSet};
use std::iter;
#[derive(Serialize, Deserialize, PartialEq)]
pub struct ParkingSimState {
#[serde(
serialize_with = "serialize_btreemap",
deserialize_with = "deserialize_btreemap"
)]
cars: BTreeMap<CarID, ParkedCar>,
// TODO hacky, but other types of lanes just mark 0 spots. :\
lanes: Vec<ParkingLane>,
}
impl ParkingSimState {
pub fn new(map: &Map) -> ParkingSimState {
ParkingSimState {
cars: BTreeMap::new(),
lanes: map
.all_lanes()
.iter()
.map(|l| ParkingLane::new(l))
.collect(),
}
}
pub fn edit_remove_lane(&mut self, id: LaneID) {
assert!(self.lanes[id.0].is_empty());
self.lanes[id.0] = ParkingLane {
id,
spots: Vec::new(),
occupants: Vec::new(),
};
}
pub fn edit_add_lane(&mut self, l: &Lane) {
self.lanes[l.id.0] = ParkingLane::new(l);
}
// TODO bad name
pub fn total_count(&self) -> usize {
self.cars.len()
}
pub fn get_free_spots(&self, lane: LaneID) -> Vec<ParkingSpot> {
let l = &self.lanes[lane.0];
let mut spots: Vec<ParkingSpot> = Vec::new();
for (idx, maybe_occupant) in l.occupants.iter().enumerate() {
if maybe_occupant.is_none() {
spots.push(ParkingSpot::new(l.id, idx));
}
}
spots
}
pub fn remove_parked_car(&mut self, p: ParkedCar) {
self.cars.remove(&p.car);
self.lanes[p.spot.lane.0].remove_parked_car(p.car);
}
pub fn add_parked_car(&mut self, p: ParkedCar) {
let spot = p.spot;
assert_eq!(self.lanes[spot.lane.0].occupants[spot.idx], None);
self.lanes[spot.lane.0].occupants[spot.idx] = Some(p.car);
self.cars.insert(p.car, p);
}
pub fn get_draw_cars(&self, id: LaneID, map: &Map) -> Vec<DrawCarInput> {
self.lanes[id.0]
.occupants
.iter()
.filter_map(|maybe_occupant| {
if let Some(car) = maybe_occupant {
Some(self.get_draw_car(*car, map).unwrap())
} else {
None
}
})
.collect()
}
pub fn get_draw_car(&self, id: CarID, map: &Map) -> Option<DrawCarInput> {
let p = self.cars.get(&id)?;
let lane = p.spot.lane;
let front_dist = self.lanes[lane.0].spots[p.spot.idx].dist_along_for_car(&p.vehicle);
Some(DrawCarInput {
id: p.car,
waiting_for_turn: None,
stopping_trace: None,
state: CarState::Parked,
vehicle_type: VehicleType::Car,
on: Traversable::Lane(lane),
body: map
.get_l(lane)
.lane_center_pts
.slice(front_dist - p.vehicle.length, front_dist)
.unwrap()
.0,
})
}
pub fn get_all_draw_cars(&self, map: &Map) -> Vec<DrawCarInput> {
self.cars
.keys()
.map(|id| self.get_draw_car(*id, map).unwrap())
.collect()
}
pub fn lookup_car(&self, id: CarID) -> Option<&ParkedCar> {
self.cars.get(&id)
}
pub fn get_first_free_spot(
&self,
parking_pos: Position,
vehicle: &Vehicle,
) -> Option<ParkingSpot> {
let l = &self.lanes[parking_pos.lane().0];
let idx = l.occupants.iter().enumerate().position(|(idx, x)| {
x.is_none() && parking_pos.dist_along() <= l.spots[idx].dist_along_for_car(vehicle)
})?;
Some(ParkingSpot::new(parking_pos.lane(), idx))
}
pub fn get_car_at_spot(&self, spot: ParkingSpot) -> Option<ParkedCar> {
let car = self.lanes[spot.lane.0].occupants[spot.idx]?;
Some(self.cars[&car].clone())
}
pub fn spot_to_driving_pos(
&self,
spot: ParkingSpot,
vehicle: &Vehicle,
driving_lane: LaneID,
map: &Map,
) -> Position {
Position::new(spot.lane, self.get_spot(spot).dist_along_for_car(vehicle))
.equiv_pos(driving_lane, map)
}
pub fn spot_to_sidewalk_pos(&self, spot: ParkingSpot, sidewalk: LaneID, map: &Map) -> Position {
Position::new(spot.lane, self.get_spot(spot).dist_along_for_ped()).equiv_pos(sidewalk, map)
}
fn get_spot(&self, spot: ParkingSpot) -> &ParkingSpotGeometry {
&self.lanes[spot.lane.0].spots[spot.idx]
}
pub fn tooltip_lines(&self, id: CarID) -> Vec<String> {
let c = self.lookup_car(id).unwrap();
vec![format!("{} is parked, owned by {:?}", c.car, c.owner)]
}
pub fn get_parked_cars_by_owner(&self, id: BuildingID) -> Vec<&ParkedCar> {
let mut result: Vec<&ParkedCar> = Vec::new();
for p in self.cars.values() {
if p.owner == Some(id) {
result.push(p);
}
}
result
}
pub fn get_owner_of_car(&self, id: CarID) -> Option<BuildingID> {
self.lookup_car(id).and_then(|p| p.owner)
}
pub fn count(&self, lanes: &HashSet<LaneID>) -> (usize, usize) {
// TODO self.cars.len() works for cars_parked; we could maintain the other value easily too
let mut cars_parked = 0;
let mut open_parking_spots = 0;
for id in lanes {
for maybe_car in &self.lanes[id.0].occupants {
if maybe_car.is_some() {
cars_parked += 1;
} else {
open_parking_spots += 1;
}
}
}
(cars_parked, open_parking_spots)
}
}
#[derive(Serialize, Deserialize, PartialEq)]
struct ParkingLane {
id: LaneID,
spots: Vec<ParkingSpotGeometry>,
occupants: Vec<Option<CarID>>,
}
impl ParkingLane {
fn new(l: &Lane) -> ParkingLane {
if l.lane_type != LaneType::Parking {
return ParkingLane {
id: l.id,
spots: Vec::new(),
occupants: Vec::new(),
};
}
ParkingLane {
id: l.id,
occupants: iter::repeat(None).take(l.number_parking_spots()).collect(),
spots: (0..l.number_parking_spots())
.map(|idx| {
let spot_start = map_model::PARKING_SPOT_LENGTH * (2.0 + idx as f64);
let (pos, angle) = l.dist_along(spot_start);
ParkingSpotGeometry {
dist_along: spot_start,
pos,
angle,
}
})
.collect(),
}
}
fn remove_parked_car(&mut self, car: CarID) {
let idx = self.occupants.iter().position(|x| *x == Some(car)).unwrap();
self.occupants[idx] = None;
}
fn is_empty(&self) -> bool {
!self.occupants.iter().any(|x| x.is_some())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct ParkingSpotGeometry {
// These 3 are of the front of the parking spot (farthest along)
dist_along: Distance,
pos: Pt2D,
angle: Angle,
}
impl ParkingSpotGeometry {
fn dist_along_for_ped(&self) -> Distance {
// Always centered in the entire parking spot
self.dist_along - (map_model::PARKING_SPOT_LENGTH / 2.0)
}
fn dist_along_for_car(&self, vehicle: &Vehicle) -> Distance {
// Find the offset to center this particular car in the parking spot
self.dist_along - (map_model::PARKING_SPOT_LENGTH - vehicle.length) / 2.0
}
}

View File

@ -33,7 +33,9 @@ impl Queue {
for car in &self.cars {
let bound = match result.last() {
Some((leader, last_dist)) => *last_dist - leader.vehicle_len - FOLLOWING_DISTANCE,
Some((leader, last_dist)) => {
*last_dist - leader.vehicle.length - FOLLOWING_DISTANCE
}
None => self.geom_len,
};
@ -42,7 +44,7 @@ impl Queue {
dump_cars(&result, self.id, time);
panic!(
"Queue has spillover on {:?} at {} -- can't draw {}, bound is {}",
self.id, time, car.id, bound
self.id, time, car.vehicle.id, bound
);
}
@ -80,7 +82,7 @@ impl Queue {
// Are we too close to the leader?
if idx != 0
&& dists[idx - 1].1 - dists[idx - 1].0.vehicle_len - FOLLOWING_DISTANCE < start_dist
&& dists[idx - 1].1 - dists[idx - 1].0.vehicle.length - FOLLOWING_DISTANCE < start_dist
{
return None;
}
@ -96,7 +98,7 @@ impl Queue {
// This could also be implemented by calling get_idx_to_insert_car with start_dist =
// self.geom_len
match self.get_car_positions(time).last() {
Some((car, front)) => *front >= car.vehicle_len + FOLLOWING_DISTANCE,
Some((car, front)) => *front >= car.vehicle.length + FOLLOWING_DISTANCE,
None => true,
}
}
@ -108,7 +110,7 @@ fn validate_positions(
id: Traversable,
) -> Vec<(&Car, Distance)> {
for pair in cars.windows(2) {
if pair[0].1 - pair[0].0.vehicle_len - FOLLOWING_DISTANCE < pair[1].1 {
if pair[0].1 - pair[0].0.vehicle.length - FOLLOWING_DISTANCE < pair[1].1 {
dump_cars(&cars, id, time);
panic!(
"get_car_positions wound up with bad positioning: {} then {}\n{:?}",
@ -122,7 +124,10 @@ fn validate_positions(
fn dump_cars(cars: &Vec<(&Car, Distance)>, id: Traversable, time: Duration) {
println!("\nOn {:?} at {}...", id, time);
for (car, dist) in cars {
println!("- {} @ {} (length {})", car.id, dist, car.vehicle_len);
println!(
"- {} @ {} (length {})",
car.vehicle.id, dist, car.vehicle.length
);
match car.state {
CarState::Crossing(ref time_int, ref dist_int) => {
println!(

View File

@ -45,11 +45,6 @@ impl CarID {
pub fn tmp_new(idx: usize, vt: VehicleType) -> CarID {
CarID(idx, vt)
}
// TODO Not sure if the new DES model should do this
pub fn tmp_get_vehicle_type(self) -> VehicleType {
self.1
}
}
impl fmt::Display for CarID {