mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
slightly different speed limits
This commit is contained in:
parent
6d70605355
commit
432c9644fc
@ -13,6 +13,7 @@
|
||||
|
||||
- better visualization
|
||||
- draw moving / blocked colors (gradually more red as they wait longer)
|
||||
- make lookahead buffer follow the shape of the road and extend into other lanes and stuff
|
||||
|
||||
- start implementing a second AORTAish driving model
|
||||
- then make cars park/unpark at the correct position
|
||||
|
@ -1,3 +1,4 @@
|
||||
use dimensioned::si;
|
||||
use geom::PolyLine;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
@ -135,4 +136,15 @@ impl Road {
|
||||
}
|
||||
panic!("{} doesn't contain {}", self.id, lane);
|
||||
}
|
||||
|
||||
pub fn get_speed_limit(&self) -> si::MeterPerSecond<f64> {
|
||||
if self.osm_tags.get("highway") == Some(&"primary".to_string())
|
||||
|| self.osm_tags.get("highway") == Some(&"secondary".to_string())
|
||||
{
|
||||
// 40mph
|
||||
return 17.8816 * si::MPS;
|
||||
}
|
||||
// 20mph
|
||||
8.9408 * si::MPS
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,7 @@ use models::{choose_turn, FOLLOWING_DISTANCE};
|
||||
use multimap::MultiMap;
|
||||
use ordered_float::NotNaN;
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use {
|
||||
Acceleration, AgentID, CarID, CarState, Distance, InvariantViolated, On, Speed, Tick,
|
||||
SPEED_LIMIT,
|
||||
};
|
||||
use {Acceleration, AgentID, CarID, CarState, Distance, InvariantViolated, On, Speed, Tick};
|
||||
|
||||
// This represents an actively driving car, not a parked one
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@ -59,7 +56,8 @@ impl Car {
|
||||
let vehicle = Vehicle::typical_car();
|
||||
|
||||
// TODO could wrap this state up
|
||||
let mut dist_to_lookahead = vehicle.max_lookahead_dist(self.speed, SPEED_LIMIT);
|
||||
let mut current_speed_limit = self.on.speed_limit(map);
|
||||
let mut dist_to_lookahead = vehicle.max_lookahead_dist(self.speed, current_speed_limit);
|
||||
// TODO when we add stuff here, optionally log stuff?
|
||||
let mut constraints: Vec<Acceleration> = Vec::new();
|
||||
let mut requests: Vec<Request> = Vec::new();
|
||||
@ -77,9 +75,9 @@ impl Car {
|
||||
}
|
||||
|
||||
// Don't exceed the speed limit
|
||||
// TODO speed limit per road
|
||||
{
|
||||
let accel = vehicle.accel_to_achieve_speed_in_one_tick(self.speed, SPEED_LIMIT);
|
||||
let accel =
|
||||
vehicle.accel_to_achieve_speed_in_one_tick(self.speed, current_speed_limit);
|
||||
constraints.push(accel);
|
||||
if self.debug {
|
||||
println!(" {} needs {} to match speed limit", self.id, accel);
|
||||
@ -96,7 +94,7 @@ impl Car {
|
||||
if dist_to_lookahead + FOLLOWING_DISTANCE >= dist_behind_other {
|
||||
let accel = vehicle.accel_to_follow(
|
||||
self.speed,
|
||||
SPEED_LIMIT,
|
||||
current_speed_limit,
|
||||
&vehicle,
|
||||
dist_behind_other,
|
||||
other.speed,
|
||||
@ -157,6 +155,7 @@ impl Car {
|
||||
}
|
||||
On::Lane(l) => On::Turn(choose_turn(¤t_path, &None, l, map)),
|
||||
};
|
||||
current_speed_limit = current_on.speed_limit(map);
|
||||
current_dist_along = 0.0 * si::M;
|
||||
dist_scanned_ahead += dist_this_step;
|
||||
}
|
||||
@ -331,7 +330,7 @@ impl DrivingSimState {
|
||||
s
|
||||
}
|
||||
|
||||
pub fn populate_info_for_intersections(&self, info: &mut AgentInfo) {
|
||||
pub fn populate_info_for_intersections(&self, info: &mut AgentInfo, _map: &Map) {
|
||||
for c in self.cars.values() {
|
||||
let id = AgentID::Car(c.id);
|
||||
info.speeds.insert(id, c.speed);
|
||||
@ -498,6 +497,7 @@ impl DrivingSimState {
|
||||
_time: Tick,
|
||||
car: CarID,
|
||||
mut path: VecDeque<LaneID>,
|
||||
_map: &Map,
|
||||
) -> bool {
|
||||
let start = path.pop_front().unwrap();
|
||||
|
||||
|
@ -67,10 +67,6 @@ pub const TIMESTEP: Time = si::Second {
|
||||
value_unsafe: 0.1,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
pub const SPEED_LIMIT: Speed = si::MeterPerSecond {
|
||||
value_unsafe: 8.9408,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
// Represents a moment in time, not a duration/delta
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
@ -122,14 +118,14 @@ pub(crate) enum On {
|
||||
}
|
||||
|
||||
impl On {
|
||||
pub(crate) fn as_lane(&self) -> LaneID {
|
||||
pub fn as_lane(&self) -> LaneID {
|
||||
match self {
|
||||
&On::Lane(id) => id,
|
||||
&On::Turn(_) => panic!("not a lane"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_turn(&self) -> TurnID {
|
||||
pub fn as_turn(&self) -> TurnID {
|
||||
match self {
|
||||
&On::Turn(id) => id,
|
||||
&On::Lane(_) => panic!("not a turn"),
|
||||
@ -156,6 +152,13 @@ impl On {
|
||||
&On::Turn(id) => map.get_t(id).dist_along(dist),
|
||||
}
|
||||
}
|
||||
|
||||
fn speed_limit(&self, map: &Map) -> Speed {
|
||||
match self {
|
||||
&On::Lane(id) => map.get_lane_and_parent(id).1.get_speed_limit(),
|
||||
&On::Turn(id) => map.get_lane_and_parent(id.dst).1.get_speed_limit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CarState {
|
||||
|
@ -14,7 +14,7 @@ use map_model::{LaneID, LaneType, Map, TurnID};
|
||||
use models::{choose_turn, Action, FOLLOWING_DISTANCE};
|
||||
use multimap::MultiMap;
|
||||
use std::collections::{BTreeMap, HashSet, VecDeque};
|
||||
use {AgentID, CarID, CarState, Distance, InvariantViolated, On, Tick, SPEED_LIMIT};
|
||||
use {AgentID, CarID, CarState, Distance, InvariantViolated, On, Tick};
|
||||
|
||||
// This represents an actively driving car, not a parked one
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@ -51,7 +51,7 @@ impl Car {
|
||||
if let Some(on) = self.waiting_for {
|
||||
on
|
||||
} else {
|
||||
let dist = SPEED_LIMIT * (time - self.started_at).as_time();
|
||||
let dist = self.on.speed_limit(map) * (time - self.started_at).as_time();
|
||||
if dist < self.on.length(map) {
|
||||
return Action::Continue;
|
||||
}
|
||||
@ -71,8 +71,8 @@ impl Car {
|
||||
// Can we actually go there right now?
|
||||
// In a more detailed driving model, this would do things like lookahead.
|
||||
let has_room_now = match desired_on {
|
||||
On::Lane(id) => sim.lanes[id.0].room_at_end(time, &sim.cars),
|
||||
On::Turn(id) => sim.turns[&id].room_at_end(time, &sim.cars),
|
||||
On::Lane(id) => sim.lanes[id.0].room_at_end(time, &sim.cars, map),
|
||||
On::Turn(id) => sim.turns[&id].room_at_end(time, &sim.cars, map),
|
||||
};
|
||||
let is_lead_vehicle = match self.on {
|
||||
On::Lane(id) => sim.lanes[id.0].cars_queue[0] == self.id,
|
||||
@ -115,7 +115,7 @@ impl Car {
|
||||
|
||||
// Returns the angle and the dist along the lane/turn too
|
||||
fn get_best_case_pos(&self, time: Tick, map: &Map) -> (Pt2D, Angle, Distance) {
|
||||
let mut dist = SPEED_LIMIT * (time - self.started_at).as_time();
|
||||
let mut dist = self.on.speed_limit(map) * (time - self.started_at).as_time();
|
||||
if self.waiting_for.is_some() {
|
||||
dist = self.on.length(map);
|
||||
}
|
||||
@ -143,7 +143,7 @@ impl SimQueue {
|
||||
// TODO it'd be cool to contribute tooltips (like number of cars currently here, capacity) to
|
||||
// tooltip
|
||||
|
||||
fn room_at_end(&self, time: Tick, cars: &BTreeMap<CarID, Car>) -> bool {
|
||||
fn room_at_end(&self, time: Tick, cars: &BTreeMap<CarID, Car>, map: &Map) -> bool {
|
||||
if self.cars_queue.is_empty() {
|
||||
return true;
|
||||
}
|
||||
@ -154,13 +154,14 @@ impl SimQueue {
|
||||
// isn't filled, then we know for sure that there's room, because in this model, we assume
|
||||
// none of the cars just arbitrarily slow down or stop without reason.
|
||||
(time - cars[self.cars_queue.last().unwrap()].started_at).as_time()
|
||||
>= FOLLOWING_DISTANCE / SPEED_LIMIT
|
||||
>= FOLLOWING_DISTANCE / self.id.speed_limit(map)
|
||||
}
|
||||
|
||||
fn reset(
|
||||
&mut self,
|
||||
ids: &Vec<CarID>,
|
||||
cars: &BTreeMap<CarID, Car>,
|
||||
map: &Map,
|
||||
) -> Result<(), InvariantViolated> {
|
||||
let old_queue = self.cars_queue.clone();
|
||||
|
||||
@ -170,7 +171,7 @@ impl SimQueue {
|
||||
self.cars_queue.sort_by_key(|id| cars[id].started_at);
|
||||
|
||||
// assert here we're not squished together too much
|
||||
let min_dt = FOLLOWING_DISTANCE / SPEED_LIMIT;
|
||||
let min_dt = FOLLOWING_DISTANCE / self.id.speed_limit(map);
|
||||
for slice in self.cars_queue.windows(2) {
|
||||
let (c1, c2) = (slice[0], slice[1]);
|
||||
let (t1, t2) = (
|
||||
@ -196,7 +197,7 @@ impl SimQueue {
|
||||
}
|
||||
|
||||
// TODO base this on actual speed ;)
|
||||
let stopping_dist = Vehicle::typical_car().stopping_distance(SPEED_LIMIT);
|
||||
let stopping_dist = Vehicle::typical_car().stopping_distance(self.id.speed_limit(map));
|
||||
|
||||
let mut results = Vec::new();
|
||||
let (pos1, angle1, dist_along1) =
|
||||
@ -277,7 +278,7 @@ impl DrivingSimState {
|
||||
s
|
||||
}
|
||||
|
||||
pub fn populate_info_for_intersections(&self, info: &mut AgentInfo) {
|
||||
pub fn populate_info_for_intersections(&self, info: &mut AgentInfo, map: &Map) {
|
||||
for c in self.cars.values() {
|
||||
let id = AgentID::Car(c.id);
|
||||
info.speeds.insert(
|
||||
@ -285,7 +286,7 @@ impl DrivingSimState {
|
||||
if c.waiting_for.is_some() {
|
||||
0.0 * si::MPS
|
||||
} else {
|
||||
SPEED_LIMIT
|
||||
c.on.speed_limit(map)
|
||||
},
|
||||
);
|
||||
info.leaders.insert(id);
|
||||
@ -433,17 +434,17 @@ impl DrivingSimState {
|
||||
// Reset all queues
|
||||
for l in &mut self.lanes {
|
||||
if let Some(v) = cars_per_lane.get_vec(&l.id.as_lane()) {
|
||||
l.reset(v, &self.cars)?;
|
||||
l.reset(v, &self.cars, map)?;
|
||||
} else {
|
||||
l.reset(&Vec::new(), &self.cars)?;
|
||||
l.reset(&Vec::new(), &self.cars, map)?;
|
||||
}
|
||||
//l.reset(cars_per_lane.get_vec(&l.id).unwrap_or_else(|| &Vec::new()), &self.cars);
|
||||
}
|
||||
for t in self.turns.values_mut() {
|
||||
if let Some(v) = cars_per_turn.get_vec(&t.id.as_turn()) {
|
||||
t.reset(v, &self.cars)?;
|
||||
t.reset(v, &self.cars, map)?;
|
||||
} else {
|
||||
t.reset(&Vec::new(), &self.cars)?;
|
||||
t.reset(&Vec::new(), &self.cars, map)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,10 +460,11 @@ impl DrivingSimState {
|
||||
time: Tick,
|
||||
car: CarID,
|
||||
mut path: VecDeque<LaneID>,
|
||||
map: &Map,
|
||||
) -> bool {
|
||||
let start = path.pop_front().unwrap();
|
||||
|
||||
if !self.lanes[start.0].room_at_end(time, &self.cars) {
|
||||
if !self.lanes[start.0].room_at_end(time, &self.cars, map) {
|
||||
// TODO car should enter Unparking state and wait for room
|
||||
println!("No room for {} to start driving on {}", car, start);
|
||||
return false;
|
||||
|
@ -76,7 +76,7 @@ macro_rules! delegate {
|
||||
}
|
||||
|
||||
impl DrivingModel {
|
||||
delegate!(fn populate_info_for_intersections(&self, info: &mut AgentInfo));
|
||||
delegate!(fn populate_info_for_intersections(&self, info: &mut AgentInfo, map: &Map));
|
||||
delegate!(fn get_car_state(&self, c: CarID) -> CarState);
|
||||
delegate!(fn get_active_and_waiting_count(&self) -> (usize, usize));
|
||||
delegate!(fn tooltip_lines(&self, id: CarID) -> Option<Vec<String>>);
|
||||
@ -90,7 +90,8 @@ impl DrivingModel {
|
||||
&mut self,
|
||||
time: Tick,
|
||||
car: CarID,
|
||||
path: VecDeque<LaneID>
|
||||
path: VecDeque<LaneID>,
|
||||
map: &Map
|
||||
) -> bool);
|
||||
delegate!(fn get_empty_lanes(&self, map: &Map) -> Vec<LaneID>);
|
||||
delegate!(fn get_draw_car(&self, id: CarID, time: Tick, map: &Map) -> Option<DrawCar>);
|
||||
@ -226,7 +227,7 @@ impl Sim {
|
||||
{
|
||||
if let Some(car) = self.parking_state.get_last_parked_car(parking_lane) {
|
||||
if self.driving_state
|
||||
.start_car_on_lane(self.time, car, VecDeque::from(steps))
|
||||
.start_car_on_lane(self.time, car, VecDeque::from(steps), map)
|
||||
{
|
||||
self.parking_state.remove_last_parked_car(parking_lane, car);
|
||||
return true;
|
||||
@ -343,7 +344,7 @@ impl Sim {
|
||||
leaders: HashSet::new(),
|
||||
};
|
||||
self.driving_state
|
||||
.populate_info_for_intersections(&mut info);
|
||||
.populate_info_for_intersections(&mut info, map);
|
||||
self.walking_state
|
||||
.populate_info_for_intersections(&mut info);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user