diff --git a/data/system/assets/tools/uphill.svg b/data/system/assets/tools/uphill.svg
new file mode 100644
index 0000000000..6ef9200c99
--- /dev/null
+++ b/data/system/assets/tools/uphill.svg
@@ -0,0 +1,4 @@
+
diff --git a/game/src/challenges/prebake.rs b/game/src/challenges/prebake.rs
index 8803bb68d6..ddab1139b9 100644
--- a/game/src/challenges/prebake.rs
+++ b/game/src/challenges/prebake.rs
@@ -131,7 +131,7 @@ fn prebake(
}
PrebakeSummary {
map: scenario.map_name.describe(),
- scenario: scenario.scenario_name.clone(),
+ scenario: scenario.scenario_name,
finished_trips,
cancelled_trips,
total_trip_duration_seconds,
diff --git a/game/src/info/building.rs b/game/src/info/building.rs
index 5de55c2fb7..ded741dff5 100644
--- a/game/src/info/building.rs
+++ b/game/src/info/building.rs
@@ -306,6 +306,7 @@ pub fn draw_occupants(details: &mut Details, app: &App, id: BuildingID, focus: O
pos,
facing: Angle::degrees(90.0),
waiting_for_turn: None,
+ intent: None,
preparing_bike: false,
// Both hands and feet!
waiting_for_bus: true,
diff --git a/geom/src/distance.rs b/geom/src/distance.rs
index 16d299ebb5..109aeea01d 100644
--- a/geom/src/distance.rs
+++ b/geom/src/distance.rs
@@ -125,16 +125,14 @@ impl Distance {
Distance::feet(10.0 * (ft / 10.0).ceil())
} else if miles < 0.1 {
Distance::feet(100.0 * (ft / 100.0).ceil())
+ } else if miles <= 1.0 {
+ Distance::miles((miles * 10.0).ceil() / 10.0)
+ } else if miles <= 10.0 {
+ Distance::miles(miles.ceil())
+ } else if miles <= 100.0 {
+ Distance::miles(10.0 * (miles / 10.0).ceil())
} else {
- if miles <= 1.0 {
- Distance::miles((miles * 10.0).ceil() / 10.0)
- } else if miles <= 10.0 {
- Distance::miles(miles.ceil())
- } else if miles <= 100.0 {
- Distance::miles(10.0 * (miles / 10.0).ceil())
- } else {
- self
- }
+ self
}
}
}
diff --git a/map_gui/src/render/bike.rs b/map_gui/src/render/bike.rs
index 4be6e527bf..40cbff8f4f 100644
--- a/map_gui/src/render/bike.rs
+++ b/map_gui/src/render/bike.rs
@@ -1,6 +1,6 @@
use geom::{ArrowCap, Circle, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Map, SIDEWALK_THICKNESS};
-use sim::{CarID, DrawCarInput, Sim};
+use sim::{CarID, DrawCarInput, Intent, Sim};
use widgetry::{Drawable, GeomBatch, GfxCtx, Prerender};
use crate::colors::ColorScheme;
@@ -99,6 +99,25 @@ impl DrawBike {
);
}
+ if input.intent == Some(Intent::SteepUphill) {
+ let bubble_z = -0.0001;
+ let mut bubble_batch =
+ GeomBatch::load_svg(prerender, "system/assets/map/thought_bubble.svg")
+ .scale(0.05)
+ .centered_on(input.body.middle())
+ .translate(2.0, -3.5)
+ .set_z_offset(bubble_z);
+ bubble_batch.append(
+ GeomBatch::load_svg(prerender, "system/assets/tools/uphill.svg")
+ .scale(0.05)
+ .centered_on(input.body.middle())
+ .translate(2.2, -4.2)
+ .set_z_offset(bubble_z),
+ );
+
+ draw_default.append(bubble_batch);
+ }
+
let zorder = input
.partly_on
.into_iter()
diff --git a/map_gui/src/render/car.rs b/map_gui/src/render/car.rs
index d0116a7544..9b19c23bc2 100644
--- a/map_gui/src/render/car.rs
+++ b/map_gui/src/render/car.rs
@@ -1,6 +1,6 @@
use geom::{Angle, ArrowCap, Distance, PolyLine, Polygon, Pt2D, Ring};
use map_model::{Map, TurnType};
-use sim::{CarID, CarStatus, DrawCarInput, Sim, VehicleType};
+use sim::{CarID, CarStatus, DrawCarInput, Intent, Sim, VehicleType};
use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
use crate::colors::ColorScheme;
@@ -90,7 +90,7 @@ impl DrawCar {
);
}
- if input.show_parking_intent {
+ if input.intent == Some(Intent::Parking) {
// draw intent bubble
let bubble_z = -0.0001;
let mut bubble_batch =
diff --git a/map_gui/src/render/pedestrian.rs b/map_gui/src/render/pedestrian.rs
index 1a55336859..28df9b5287 100644
--- a/map_gui/src/render/pedestrian.rs
+++ b/map_gui/src/render/pedestrian.rs
@@ -1,6 +1,6 @@
use geom::{ArrowCap, Circle, Distance, PolyLine, Polygon, Pt2D};
use map_model::{DrivingSide, Map, SIDEWALK_THICKNESS};
-use sim::{DrawPedCrowdInput, DrawPedestrianInput, PedCrowdLocation, PedestrianID, Sim};
+use sim::{DrawPedCrowdInput, DrawPedestrianInput, Intent, PedCrowdLocation, PedestrianID, Sim};
use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
use crate::colors::ColorScheme;
@@ -43,6 +43,25 @@ impl DrawPedestrian {
);
}
+ if input.intent == Some(Intent::SteepUphill) {
+ let bubble_z = -0.0001;
+ let mut bubble_batch =
+ GeomBatch::load_svg(prerender, "system/assets/map/thought_bubble.svg")
+ .scale(0.05)
+ .centered_on(input.pos)
+ .translate(2.0, -3.5)
+ .set_z_offset(bubble_z);
+ bubble_batch.append(
+ GeomBatch::load_svg(prerender, "system/assets/tools/uphill.svg")
+ .scale(0.05)
+ .centered_on(input.pos)
+ .translate(2.2, -4.2)
+ .set_z_offset(bubble_z),
+ );
+
+ draw_default.append(bubble_batch);
+ }
+
DrawPedestrian {
id: input.id,
body_circle,
diff --git a/map_model/src/pathfind/vehicles.rs b/map_model/src/pathfind/vehicles.rs
index 6dd04271a5..a7d06de5e0 100644
--- a/map_model/src/pathfind/vehicles.rs
+++ b/map_model/src/pathfind/vehicles.rs
@@ -260,7 +260,7 @@ pub fn vehicle_cost(
PathConstraints::Pedestrian => unreachable!(),
};
let t1 = map.get_r(dr.id).center_pts.length()
- / Traversable::max_speed_along_road(dr, max_speed, constraints, map);
+ / Traversable::max_speed_along_road(dr, max_speed, constraints, map).0;
let t2 =
mvmnt_length / Traversable::max_speed_along_movement(mvmnt, max_speed, constraints, map);
diff --git a/map_model/src/traversable.rs b/map_model/src/traversable.rs
index 6b2f08a093..8c22091cf2 100644
--- a/map_model/src/traversable.rs
+++ b/map_model/src/traversable.rs
@@ -202,6 +202,18 @@ impl Traversable {
constraints: PathConstraints,
map: &Map,
) -> Speed {
+ self.max_speed_and_incline_along(max_speed_on_flat_ground, constraints, map)
+ .0
+ }
+
+ /// The single definitive place to determine how fast somebody could go along a single road or
+ /// turn. This should be used for pathfinding and simulation. Returns (speed, percent incline).
+ pub fn max_speed_and_incline_along(
+ &self,
+ max_speed_on_flat_ground: Option,
+ constraints: PathConstraints,
+ map: &Map,
+ ) -> (Speed, f64) {
match self {
Traversable::Lane(l) => Traversable::max_speed_along_road(
map.get_l(*l).get_directed_parent(),
@@ -209,23 +221,26 @@ impl Traversable {
constraints,
map,
),
- Traversable::Turn(t) => Traversable::max_speed_along_movement(
- t.to_movement(map),
- max_speed_on_flat_ground,
- constraints,
- map,
+ Traversable::Turn(t) => (
+ Traversable::max_speed_along_movement(
+ t.to_movement(map),
+ max_speed_on_flat_ground,
+ constraints,
+ map,
+ ),
+ 0.0,
),
}
}
/// The single definitive place to determine how fast somebody could go along a single road.
- /// This should be used for pathfinding and simulation.
- pub fn max_speed_along_road(
+ /// This should be used for pathfinding and simulation. Returns (speed, percent incline).
+ pub(crate) fn max_speed_along_road(
dr: DirectedRoadID,
max_speed_on_flat_ground: Option,
constraints: PathConstraints,
map: &Map,
- ) -> Speed {
+ ) -> (Speed, f64) {
let road = map.get_r(dr.id);
let percent_incline = if dr.dir == Direction::Fwd {
road.percent_incline
@@ -245,16 +260,17 @@ impl Traversable {
road.speed_limit
};
- if let Some(s) = max_speed_on_flat_ground {
+ let speed = if let Some(s) = max_speed_on_flat_ground {
base.min(s)
} else {
base
- }
+ };
+ (speed, percent_incline)
}
/// The single definitive place to determine how fast somebody could go along a single
- /// movement. This should be used for pathfinding and simulation.
- pub fn max_speed_along_movement(
+ /// movement. This should be used for pathfinding and simulation. Ignores elevation.
+ pub(crate) fn max_speed_along_movement(
mvmnt: MovementID,
max_speed_on_flat_ground: Option,
_: PathConstraints,
diff --git a/sim/src/lib.rs b/sim/src/lib.rs
index 4076cb75cc..e184b6c6dc 100644
--- a/sim/src/lib.rs
+++ b/sim/src/lib.rs
@@ -29,7 +29,7 @@ use map_model::{
};
pub use crate::render::{
- CarStatus, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, PedCrowdLocation,
+ CarStatus, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, Intent, PedCrowdLocation,
UnzoomedAgent,
};
diff --git a/sim/src/mechanics/car.rs b/sim/src/mechanics/car.rs
index d961d33915..8fbf42cef8 100644
--- a/sim/src/mechanics/car.rs
+++ b/sim/src/mechanics/car.rs
@@ -6,8 +6,8 @@ use geom::{Distance, Duration, PolyLine, Time, EPSILON_DIST};
use map_model::{Direction, LaneID, Map, Traversable};
use crate::{
- CarID, CarStatus, DistanceInterval, DrawCarInput, ParkingSpot, PersonID, Router, TimeInterval,
- TransitSimState, TripID, Vehicle, VehicleType,
+ CarID, CarStatus, DistanceInterval, DrawCarInput, Intent, ParkingSpot, PersonID, Router,
+ TimeInterval, TransitSimState, TripID, Vehicle, VehicleType,
};
/// Represents a single vehicle. Note "car" is a misnomer; it could also be a bus or bike.
@@ -51,13 +51,17 @@ impl Car {
start_time: Time,
map: &Map,
) -> CarState {
- let speed = self.router.head().max_speed_along(
+ let (speed, percent_incline) = self.router.head().max_speed_and_incline_along(
self.vehicle.max_speed,
self.vehicle.vehicle_type.to_constraints(),
map,
);
let dt = (dist_int.end - dist_int.start) / speed;
- CarState::Crossing(TimeInterval::new(start_time, start_time + dt), dist_int)
+ CarState::Crossing {
+ time_int: TimeInterval::new(start_time, start_time + dt),
+ dist_int,
+ steep_uphill: percent_incline >= 0.08,
+ }
}
pub fn get_draw_car(
@@ -262,17 +266,23 @@ impl Car {
status: match self.state {
CarState::Queued { .. } => CarStatus::Moving,
CarState::WaitingToAdvance { .. } => CarStatus::Moving,
- CarState::Crossing(_, _) => CarStatus::Moving,
+ CarState::Crossing { .. } => CarStatus::Moving,
CarState::ChangingLanes { .. } => CarStatus::Moving,
CarState::Unparking { .. } => CarStatus::Moving,
CarState::Parking(_, _, _) => CarStatus::Moving,
// Changing color for idling buses is helpful
CarState::IdlingAtStop(_, _) => CarStatus::Parked,
},
- show_parking_intent: matches!(
- (self.is_parking(), &self.state),
- (true, _) | (_, CarState::Unparking { .. })
- ),
+ intent: if self.is_parking() || matches!(self.state, CarState::Unparking { .. }) {
+ Some(Intent::Parking)
+ } else {
+ match self.state {
+ CarState::Crossing { steep_uphill, .. } if steep_uphill => {
+ Some(Intent::SteepUphill)
+ }
+ _ => None,
+ }
+ },
on: self.router.head(),
partly_on,
label: if self.vehicle.vehicle_type == VehicleType::Bus
@@ -303,7 +313,11 @@ impl Car {
/// state machine encoded here.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) enum CarState {
- Crossing(TimeInterval, DistanceInterval),
+ Crossing {
+ time_int: TimeInterval,
+ dist_int: DistanceInterval,
+ steep_uphill: bool,
+ },
ChangingLanes {
from: LaneID,
to: LaneID,
@@ -334,7 +348,7 @@ pub(crate) enum CarState {
impl CarState {
pub fn get_end_time(&self) -> Time {
match self {
- CarState::Crossing(ref time_int, _) => time_int.end,
+ CarState::Crossing { ref time_int, .. } => time_int.end,
CarState::Queued { .. } => unreachable!(),
CarState::WaitingToAdvance { .. } => unreachable!(),
// Note this state lasts for lc_time, NOT for new_time.
diff --git a/sim/src/mechanics/driving.rs b/sim/src/mechanics/driving.rs
index 3fc15fbb7e..14de95d271 100644
--- a/sim/src/mechanics/driving.rs
+++ b/sim/src/mechanics/driving.rs
@@ -368,7 +368,7 @@ impl DrivingSimState {
transit: &mut TransitSimState,
) -> bool {
match car.state {
- CarState::Crossing(_, _) => {
+ CarState::Crossing { .. } => {
car.state = CarState::Queued {
blocked_since: now,
want_to_change_lanes: None,
@@ -554,7 +554,11 @@ impl DrivingSimState {
} => {
// The car is already in the target queue. Just set them in the crossing state; we
// already calculated the intervals for it.
- car.state = CarState::Crossing(new_time, new_dist);
+ car.state = CarState::Crossing {
+ time_int: new_time,
+ dist_int: new_dist,
+ steep_uphill: false,
+ };
ctx.scheduler
.push(car.state.get_end_time(), Command::UpdateCar(car.vehicle.id));
@@ -595,7 +599,7 @@ impl DrivingSimState {
let our_dist = dists[idx].front;
match car.state {
- CarState::Crossing(_, _)
+ CarState::Crossing { .. }
| CarState::Unparking { .. }
| CarState::WaitingToAdvance { .. }
| CarState::ChangingLanes { .. } => unreachable!(),
@@ -709,7 +713,7 @@ impl DrivingSimState {
/*
// If this car wasn't blocked at all, when would it reach its goal?
let ideal_end_time = match car.crossing_state(our_dist, now, map) {
- CarState::Crossing(time_int, _) => time_int.end,
+ CarState::Crossing { time_int, .. } => time_int.end,
_ => unreachable!(),
};
if ideal_end_time == now {
@@ -876,7 +880,7 @@ impl DrivingSimState {
Command::UpdateCar(follower_id),
);
}
- CarState::Crossing(_, _) => {
+ CarState::Crossing { .. } => {
// If the follower was still Crossing, they might not've been blocked by the
// leader yet. But recalculating their Crossing state isn't necessarily a no-op
// -- this could prevent them from suddenly warping past a blockage.
@@ -901,7 +905,9 @@ impl DrivingSimState {
now,
ctx.map,
) {
- CarState::Crossing(time, dist) => (time, dist),
+ CarState::Crossing {
+ time_int, dist_int, ..
+ } => (time_int, dist_int),
_ => unreachable!(),
};
assert!(new_time.end >= lc_time.end);
@@ -1051,7 +1057,7 @@ impl DrivingSimState {
CarState::WaitingToAdvance { .. } => unreachable!(),
// They weren't blocked. Note that there's no way the Crossing state could
// jump forwards here; the leader vanished from the end of the traversable.
- CarState::Crossing(_, _)
+ CarState::Crossing { .. }
| CarState::ChangingLanes { .. }
| CarState::Unparking { .. }
| CarState::Parking(_, _, _)
@@ -1151,7 +1157,9 @@ impl DrivingSimState {
now,
ctx.map,
) {
- CarState::Crossing(time, dist) => (time, dist),
+ CarState::Crossing {
+ time_int, dist_int, ..
+ } => (time_int, dist_int),
_ => unreachable!(),
};
@@ -1366,7 +1374,7 @@ impl DrivingSimState {
id: cause,
waiting_for_turn: None,
status: CarStatus::Parked,
- show_parking_intent: false,
+ intent: None,
on,
partly_on: Vec::new(),
label: Some("block".to_string()),
@@ -1383,7 +1391,7 @@ impl DrivingSimState {
id: cause,
waiting_for_turn: None,
status: CarStatus::Parked,
- show_parking_intent: false,
+ intent: None,
on,
partly_on: Vec::new(),
label: Some("block".to_string()),
diff --git a/sim/src/mechanics/parking.rs b/sim/src/mechanics/parking.rs
index 1b27376936..1aec4312b2 100644
--- a/sim/src/mechanics/parking.rs
+++ b/sim/src/mechanics/parking.rs
@@ -370,7 +370,7 @@ impl ParkingSim for NormalParkingSimState {
id: p.vehicle.id,
waiting_for_turn: None,
status: CarStatus::Parked,
- show_parking_intent: false,
+ intent: None,
on: Traversable::Lane(lane),
partly_on: Vec::new(),
label: None,
@@ -392,7 +392,7 @@ impl ParkingSim for NormalParkingSimState {
id: p.vehicle.id,
waiting_for_turn: None,
status: CarStatus::Parked,
- show_parking_intent: false,
+ intent: None,
// Just used for z-order
on: Traversable::Lane(pl.driving_pos.lane()),
partly_on: Vec::new(),
diff --git a/sim/src/mechanics/queue.rs b/sim/src/mechanics/queue.rs
index c67870bebd..b58db8b319 100644
--- a/sim/src/mechanics/queue.rs
+++ b/sim/src/mechanics/queue.rs
@@ -228,7 +228,11 @@ impl Queue {
}
self.geom_len
}
- CarState::Crossing(ref time_int, ref dist_int) => {
+ CarState::Crossing {
+ ref time_int,
+ ref dist_int,
+ ..
+ } => {
// TODO Why percent_clamp_end? We process car updates in any order, so we might
// calculate this before moving this car from Crossing to another state.
dist_int.lerp(time_int.percent_clamp_end(now)).min(bound)
@@ -575,7 +579,11 @@ fn dump_cars(dists: &[QueueEntry], cars: &FixedMap, id: Traversable,
println!("- {:?} @ {}..{}", entry.member, entry.front, entry.back);
match entry.member {
Queued::Vehicle(id) => match cars[&id].state {
- CarState::Crossing(ref time_int, ref dist_int) => {
+ CarState::Crossing {
+ ref time_int,
+ ref dist_int,
+ ..
+ } => {
println!(
" Going {} .. {} during {} .. {}",
dist_int.start, dist_int.end, time_int.start, time_int.end
diff --git a/sim/src/mechanics/walking.rs b/sim/src/mechanics/walking.rs
index 420b4be865..0713bbfe30 100644
--- a/sim/src/mechanics/walking.rs
+++ b/sim/src/mechanics/walking.rs
@@ -12,9 +12,9 @@ use map_model::{
use crate::sim::Ctx;
use crate::{
AgentID, AgentProperties, Command, CommutersVehiclesCounts, CreatePedestrian, DistanceInterval,
- DrawPedCrowdInput, DrawPedestrianInput, Event, IntersectionSimState, ParkedCar, ParkingSpot,
- PedCrowdLocation, PedestrianID, PersonID, Scheduler, SidewalkPOI, SidewalkSpot, TimeInterval,
- TransitSimState, TripID, TripManager, UnzoomedAgent,
+ DrawPedCrowdInput, DrawPedestrianInput, Event, Intent, IntersectionSimState, ParkedCar,
+ ParkingSpot, PedCrowdLocation, PedestrianID, PersonID, Scheduler, SidewalkPOI, SidewalkSpot,
+ TimeInterval, TransitSimState, TripID, TripManager, UnzoomedAgent,
};
const TIME_TO_START_BIKING: Duration = Duration::const_seconds(30.0);
@@ -60,13 +60,14 @@ impl WalkingSimState {
let mut ped = Pedestrian {
id: params.id,
// Temporary bogus thing
- state: PedState::Crossing(
- DistanceInterval::new_walking(Distance::ZERO, Distance::meters(1.0)),
- TimeInterval::new(
+ state: PedState::Crossing {
+ dist_int: DistanceInterval::new_walking(Distance::ZERO, Distance::meters(1.0)),
+ time_int: TimeInterval::new(
Time::START_OF_DAY,
Time::START_OF_DAY + Duration::seconds(1.0),
),
- ),
+ steep_uphill: false,
+ },
speed: params.speed,
total_blocked_time: Duration::ZERO,
started_at: now,
@@ -129,7 +130,7 @@ impl WalkingSimState {
) {
let mut ped = self.peds.get_mut(&id).unwrap();
match ped.state {
- PedState::Crossing(ref dist_int, _) => {
+ PedState::Crossing { ref dist_int, .. } => {
if ped.path.is_last_step() {
match ped.goal.connection {
SidewalkPOI::ParkingSpot(spot) => {
@@ -371,9 +372,11 @@ impl WalkingSimState {
}*/
let current_state_dist = match p.state {
- PedState::Crossing(ref dist_int, ref time_int) => {
- time_int.percent(now) * dist_int.length()
- }
+ PedState::Crossing {
+ ref dist_int,
+ ref time_int,
+ ..
+ } => time_int.percent(now) * dist_int.length(),
// We're at the beginning of our trip and are only walking along a driveway or biking
// connection
PedState::LeavingBuilding(_, _)
@@ -448,7 +451,7 @@ impl WalkingSimState {
let dist = ped.get_dist_along(now, map);
match ped.state {
- PedState::Crossing(ref dist_int, _) => {
+ PedState::Crossing { ref dist_int, .. } => {
if dist_int.start < dist_int.end {
forwards.push((*id, dist));
} else {
@@ -628,18 +631,26 @@ impl Pedestrian {
}
};
let dist_int = DistanceInterval::new_walking(start_dist, end_dist);
- let speed = self.path.current_step().as_traversable().max_speed_along(
- Some(self.speed),
- PathConstraints::Pedestrian,
- map,
- );
+ let (speed, percent_incline) = self
+ .path
+ .current_step()
+ .as_traversable()
+ .max_speed_and_incline_along(Some(self.speed), PathConstraints::Pedestrian, map);
let time_int = TimeInterval::new(start_time, start_time + dist_int.length() / speed);
- PedState::Crossing(dist_int, time_int)
+ PedState::Crossing {
+ dist_int,
+ time_int,
+ steep_uphill: percent_incline >= 0.08,
+ }
}
fn get_dist_along(&self, now: Time, map: &Map) -> Distance {
match self.state {
- PedState::Crossing(ref dist_int, ref time_int) => dist_int.lerp(time_int.percent(now)),
+ PedState::Crossing {
+ ref dist_int,
+ ref time_int,
+ ..
+ } => dist_int.lerp(time_int.percent(now)),
PedState::WaitingToTurn(dist, _) => dist,
PedState::LeavingBuilding(b, _) | PedState::EnteringBuilding(b, _) => {
map.get_b(b).sidewalk_pos.dist_along()
@@ -661,8 +672,13 @@ impl Pedestrian {
} else {
270.0
};
+ let mut intent = None;
let (pos, facing) = match self.state {
- PedState::Crossing(ref dist_int, ref time_int) => {
+ PedState::Crossing {
+ ref dist_int,
+ ref time_int,
+ steep_uphill,
+ } => {
let percent = if now > time_int.end {
1.0
} else {
@@ -677,6 +693,9 @@ impl Pedestrian {
} else {
orig_angle.opposite()
};
+ if steep_uphill {
+ intent = Some(Intent::SteepUphill);
+ }
(
pos.project_away(SIDEWALK_THICKNESS / 4.0, facing.rotate_degs(angle_offset)),
facing,
@@ -758,6 +777,7 @@ impl Pedestrian {
PedState::WaitingToTurn(_, _) => Some(self.path.next_step().as_turn()),
_ => None,
},
+ intent,
preparing_bike: matches!(
self.state,
PedState::StartingToBike(_, _, _) | PedState::FinishingBiking(_, _, _)
@@ -817,7 +837,11 @@ impl Pedestrian {
#[derive(Serialize, Deserialize, Debug, Clone)]
enum PedState {
- Crossing(DistanceInterval, TimeInterval),
+ Crossing {
+ dist_int: DistanceInterval,
+ time_int: TimeInterval,
+ steep_uphill: bool,
+ },
/// The Distance is either 0 or the current traversable's length. The Time is blocked_since.
WaitingToTurn(Distance, Time),
LeavingBuilding(BuildingID, TimeInterval),
@@ -832,7 +856,7 @@ enum PedState {
impl PedState {
fn get_end_time(&self) -> Time {
match self {
- PedState::Crossing(_, ref time_int) => time_int.end,
+ PedState::Crossing { ref time_int, .. } => time_int.end,
PedState::WaitingToTurn(_, _) => unreachable!(),
PedState::LeavingBuilding(_, ref time_int) => time_int.end,
PedState::EnteringBuilding(_, ref time_int) => time_int.end,
diff --git a/sim/src/render.rs b/sim/src/render.rs
index 13776274a1..a3e860db65 100644
--- a/sim/src/render.rs
+++ b/sim/src/render.rs
@@ -11,6 +11,7 @@ pub struct DrawPedestrianInput {
pub pos: Pt2D,
pub facing: Angle,
pub waiting_for_turn: Option,
+ pub intent: Option,
pub preparing_bike: bool,
pub waiting_for_bus: bool,
pub on: Traversable,
@@ -37,7 +38,7 @@ pub struct DrawCarInput {
pub id: CarID,
pub waiting_for_turn: Option,
pub status: CarStatus,
- pub show_parking_intent: bool,
+ pub intent: Option,
/// Front of the car
pub on: Traversable,
/// Possibly the rest
@@ -56,6 +57,13 @@ pub enum CarStatus {
Parked,
}
+/// Shows an agent's current inner intention or thoughts.
+#[derive(Clone, PartialEq)]
+pub enum Intent {
+ Parking,
+ SteepUphill,
+}
+
pub struct UnzoomedAgent {
pub id: AgentID,
pub pos: Pt2D,