mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
switch to new units in sim... and editor, darnit, accidentally ammended
commit
This commit is contained in:
parent
133ec037c9
commit
ac2b8f5a9a
@ -4,6 +4,9 @@
|
||||
|
||||
- try fixed pt again, for determinism purposes mostly
|
||||
- get rid of dimensioned. just wrap f64's at first and get to the new API.
|
||||
- go through and use less f64's... like LANE_THICKNESS, make_polygons, Circle::new, project_away
|
||||
- audit inner_foo()'s
|
||||
- rerun import
|
||||
|
||||
- change internal pt2d representation to int. JUST get that working first.
|
||||
- clamp distances first, not points?
|
||||
|
@ -9,7 +9,6 @@ aabb-quadtree = "0.1.0"
|
||||
abstutil = { path = "../abstutil" }
|
||||
counter = "0.4.3"
|
||||
cpuprofiler = "0.0.3"
|
||||
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
|
||||
downcast = "0.9.2"
|
||||
ezgui = { path = "../ezgui" }
|
||||
generator = "0.6"
|
||||
|
@ -1,12 +1,11 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx, Key};
|
||||
use geom::Distance;
|
||||
use map_model::{
|
||||
BuildingID, IntersectionID, IntersectionType, LaneID, LaneType, PathRequest, Pathfinder,
|
||||
Position, Trace, LANE_THICKNESS,
|
||||
};
|
||||
use std::f64;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Source {
|
||||
@ -86,7 +85,7 @@ impl Plugin for SpawnAgent {
|
||||
if recalculate {
|
||||
let start = match self.from {
|
||||
Source::Walking(from) => map.get_b(from).front_path.sidewalk,
|
||||
Source::Driving(from) => Position::new(from, 0.0 * si::M),
|
||||
Source::Driving(from) => Position::new(from, Distance::ZERO),
|
||||
};
|
||||
let end = match new_goal {
|
||||
Goal::Building(to) => match self.from {
|
||||
@ -121,10 +120,8 @@ impl Plugin for SpawnAgent {
|
||||
can_use_bus_lanes: false,
|
||||
},
|
||||
) {
|
||||
self.maybe_goal = Some((
|
||||
new_goal,
|
||||
path.trace(map, start.dist_along(), f64::MAX * si::M),
|
||||
));
|
||||
self.maybe_goal =
|
||||
Some((new_goal, path.trace(map, start.dist_along(), Distance::MAX)));
|
||||
} else {
|
||||
self.maybe_goal = None;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use crate::render::{draw_signal_cycle, draw_signal_diagram, DrawTurn};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx, Key, ScreenPt, Wizard, WrappedWizard};
|
||||
use geom::Duration;
|
||||
use map_model::{ControlTrafficSignal, Cycle, IntersectionID, Map, TurnID, TurnPriority, TurnType};
|
||||
|
||||
// TODO Warn if there are empty cycles or if some turn is completely absent from the signal.
|
||||
@ -78,12 +78,13 @@ impl Plugin for TrafficSignalEditor {
|
||||
"{}",
|
||||
ctx.primary.map.get_traffic_signal(self.i).cycles[self.current_cycle]
|
||||
.duration
|
||||
.value_unsafe as usize
|
||||
.inner_seconds() as usize
|
||||
),
|
||||
)
|
||||
{
|
||||
let mut signal = ctx.primary.map.get_traffic_signal(self.i).clone();
|
||||
signal.cycles[self.current_cycle].edit_duration((new_duration as f64) * si::S);
|
||||
signal.cycles[self.current_cycle]
|
||||
.edit_duration(Duration::seconds(new_duration as f64));
|
||||
ctx.primary.map.edit_traffic_signal(signal);
|
||||
self.cycle_duration_wizard = None;
|
||||
} else if self.cycle_duration_wizard.as_ref().unwrap().aborted() {
|
||||
|
@ -169,7 +169,7 @@ impl Plugin for SimControls {
|
||||
if ctx.input.is_update_event() {
|
||||
// TODO https://gafferongames.com/post/fix_your_timestep/
|
||||
let dt_s = elapsed_seconds(*last_step);
|
||||
if dt_s >= TIMESTEP.value_unsafe / self.desired_speed {
|
||||
if dt_s >= TIMESTEP.inner_seconds() / self.desired_speed {
|
||||
let tick = ctx.primary.sim.time;
|
||||
let events = ctx.primary.sim.step(&ctx.primary.map);
|
||||
self.primary_events = Some((tick, events));
|
||||
|
@ -1,11 +1,9 @@
|
||||
use crate::objects::Ctx;
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx, Key};
|
||||
use geom::Line;
|
||||
use geom::{Distance, Line};
|
||||
use map_model::{Trace, LANE_THICKNESS};
|
||||
use sim::{Tick, TripID};
|
||||
use std::f64;
|
||||
|
||||
pub struct DiffTripState {
|
||||
time: Tick,
|
||||
@ -90,10 +88,10 @@ fn diff_trip(trip: TripID, ctx: &mut PluginCtx) -> DiffTripState {
|
||||
};
|
||||
let primary_route = primary_sim
|
||||
.trip_to_agent(trip)
|
||||
.and_then(|agent| primary_sim.trace_route(agent, primary_map, f64::MAX * si::M));
|
||||
.and_then(|agent| primary_sim.trace_route(agent, primary_map, Distance::MAX));
|
||||
let secondary_route = secondary_sim
|
||||
.trip_to_agent(trip)
|
||||
.and_then(|agent| secondary_sim.trace_route(agent, secondary_map, f64::MAX * si::M));
|
||||
.and_then(|agent| secondary_sim.trace_route(agent, secondary_map, Distance::MAX));
|
||||
|
||||
if line.is_none() || primary_route.is_none() || secondary_route.is_none() {
|
||||
warn!("{} isn't present in both sims", trip);
|
||||
|
@ -1,10 +1,9 @@
|
||||
use crate::objects::Ctx;
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx, Key};
|
||||
use geom::Distance;
|
||||
use map_model::{Trace, LANE_THICKNESS};
|
||||
use sim::{Tick, TripID};
|
||||
use std::f64;
|
||||
|
||||
pub enum ShowRouteState {
|
||||
Inactive,
|
||||
@ -87,7 +86,7 @@ fn show_route(trip: TripID, ctx: &mut PluginCtx) -> ShowRouteState {
|
||||
if let Some(trace) = ctx
|
||||
.primary
|
||||
.sim
|
||||
.trace_route(agent, &ctx.primary.map, f64::MAX * si::M)
|
||||
.trace_route(agent, &ctx.primary.map, Distance::MAX)
|
||||
{
|
||||
ShowRouteState::Active(time, trip, Some(trace))
|
||||
} else {
|
||||
@ -108,7 +107,7 @@ fn debug_all_routes(ctx: &mut PluginCtx) -> ShowRouteState {
|
||||
let mut traces: Vec<Trace> = Vec::new();
|
||||
for trip in sim.get_stats().canonical_pt_per_trip.keys() {
|
||||
if let Some(agent) = sim.trip_to_agent(*trip) {
|
||||
if let Some(trace) = sim.trace_route(agent, &ctx.primary.map, f64::MAX * si::M) {
|
||||
if let Some(trace) = sim.trace_route(agent, &ctx.primary.map, Distance::MAX) {
|
||||
traces.push(trace);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use crate::render::{draw_signal_diagram, DrawTurn};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx, Key};
|
||||
use geom::Duration;
|
||||
use map_model::{IntersectionID, LaneID, TurnType};
|
||||
|
||||
pub struct TurnCyclerState {
|
||||
@ -95,7 +95,7 @@ impl Plugin for TurnCyclerState {
|
||||
signal.current_cycle_and_remaining_time(ctx.sim.time.as_time());
|
||||
if ctx.sim.is_in_overtime(i) {
|
||||
// TODO Hacky way of indicating overtime. Should make a 3-case enum.
|
||||
time_left = -1.0 * si::S;
|
||||
time_left = Duration::seconds(-1.0);
|
||||
}
|
||||
draw_signal_diagram(
|
||||
i,
|
||||
|
@ -63,7 +63,7 @@ impl Plugin for WarpState {
|
||||
return false;
|
||||
} else {
|
||||
ctx.canvas
|
||||
.center_on_map_pt(line.dist_along(percent * line.length()));
|
||||
.center_on_map_pt(line.dist_along(line.length() * percent));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::render::{RenderOptions, Renderable};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||
use geom::{Bounds, Line, Polygon, Pt2D};
|
||||
use geom::{Bounds, Distance, Line, Polygon, Pt2D};
|
||||
use map_model::{Building, BuildingID, LANE_THICKNESS};
|
||||
|
||||
pub struct DrawBuilding {
|
||||
@ -20,7 +19,7 @@ impl DrawBuilding {
|
||||
// overlap. For now, this cleanup is visual; it doesn't belong in the map_model layer.
|
||||
let mut front_path_line = bldg.front_path.line.clone();
|
||||
let len = front_path_line.length();
|
||||
let trim_back = LANE_THICKNESS / 2.0 * si::M;
|
||||
let trim_back = Distance::meters(LANE_THICKNESS / 2.0);
|
||||
if len > trim_back && len - trim_back > geom::EPSILON_DIST {
|
||||
front_path_line = Line::new(
|
||||
front_path_line.pt1(),
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::render::{RenderOptions, Renderable};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Bounds, PolyLine, Polygon, Pt2D};
|
||||
use geom::{Bounds, Distance, PolyLine, Polygon, Pt2D};
|
||||
use map_model::{BusStop, BusStopID, Map, LANE_THICKNESS};
|
||||
|
||||
pub struct DrawBusStop {
|
||||
@ -13,7 +12,7 @@ pub struct DrawBusStop {
|
||||
|
||||
impl DrawBusStop {
|
||||
pub fn new(stop: &BusStop, map: &Map) -> DrawBusStop {
|
||||
let radius = 2.0 * si::M;
|
||||
let radius = Distance::meters(2.0);
|
||||
// TODO if this happens to cross a bend in the lane, it'll look weird. similar to the
|
||||
// lookahead arrows and center points / dashed white, we really want to render an Interval
|
||||
// or something.
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::render::{RenderOptions, Renderable};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Angle, Bounds, Circle, PolyLine, Polygon, Pt2D};
|
||||
use geom::{Angle, Bounds, Circle, Distance, PolyLine, Polygon, Pt2D};
|
||||
use map_model::{Map, TurnType};
|
||||
use sim::{CarID, CarState, DrawCarInput, MIN_CAR_LENGTH};
|
||||
use std;
|
||||
@ -54,15 +53,18 @@ impl DrawCar {
|
||||
};
|
||||
}
|
||||
|
||||
let (front_blinker_pos, front_blinker_angle) =
|
||||
input.body.dist_along(input.body.length() - 0.5 * si::M);
|
||||
let (back_blinker_pos, back_blinker_angle) = input.body.dist_along(0.5 * si::M);
|
||||
let (front_blinker_pos, front_blinker_angle) = input
|
||||
.body
|
||||
.dist_along(input.body.length() - Distance::meters(0.5));
|
||||
let (back_blinker_pos, back_blinker_angle) = input.body.dist_along(Distance::meters(0.5));
|
||||
let blinker_radius = 0.3;
|
||||
|
||||
let window_length_gap = 0.2;
|
||||
let window_thickness = 0.3;
|
||||
let front_window = {
|
||||
let (pos, angle) = input.body.dist_along(input.body.length() - 1.0 * si::M);
|
||||
let (pos, angle) = input
|
||||
.body
|
||||
.dist_along(input.body.length() - Distance::meters(1.0));
|
||||
thick_line_from_angle(
|
||||
window_thickness,
|
||||
CAR_WIDTH - 2.0 * window_length_gap,
|
||||
@ -74,7 +76,7 @@ impl DrawCar {
|
||||
)
|
||||
};
|
||||
let back_window = {
|
||||
let (pos, angle) = input.body.dist_along(1.0 * si::M);
|
||||
let (pos, angle) = input.body.dist_along(Distance::meters(1.0));
|
||||
thick_line_from_angle(
|
||||
window_thickness * 0.8,
|
||||
CAR_WIDTH - 2.0 * window_length_gap,
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::render::{RenderOptions, Renderable, EXTRA_SHAPE_POINT_RADIUS, EXTRA_SHAPE_THICKNESS};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Bounds, Circle, GPSBounds, PolyLine, Polygon, Pt2D};
|
||||
use geom::{Bounds, Circle, Distance, GPSBounds, PolyLine, Polygon, Pt2D};
|
||||
use kml::ExtraShape;
|
||||
use map_model::{FindClosest, RoadID, LANE_THICKNESS};
|
||||
use std::collections::BTreeMap;
|
||||
@ -52,19 +51,18 @@ impl DrawExtraShape {
|
||||
})
|
||||
} else {
|
||||
let width = get_sidewalk_width(&s.attributes)
|
||||
.unwrap_or(EXTRA_SHAPE_THICKNESS * si::M)
|
||||
.value_unsafe;
|
||||
.unwrap_or(Distance::meters(EXTRA_SHAPE_THICKNESS));
|
||||
let pl = PolyLine::new(pts);
|
||||
// The blockface line endpoints will be close to other roads, so match based on the
|
||||
// middle of the blockface.
|
||||
// TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within
|
||||
// the threshold distance?
|
||||
let road = closest
|
||||
.closest_pt(pl.middle(), 5.0 * LANE_THICKNESS * si::M)
|
||||
.closest_pt(pl.middle(), Distance::meters(5.0 * LANE_THICKNESS))
|
||||
.map(|(r, _)| r);
|
||||
Some(DrawExtraShape {
|
||||
id,
|
||||
shape: Shape::Polygon(pl.make_polygons(width)),
|
||||
shape: Shape::Polygon(pl.make_polygons(width.inner_meters())),
|
||||
attributes: s.attributes,
|
||||
road,
|
||||
})
|
||||
@ -110,15 +108,14 @@ impl Renderable for DrawExtraShape {
|
||||
}
|
||||
|
||||
// See https://www.seattle.gov/Documents/Departments/SDOT/GIS/Sidewalks_OD.pdf
|
||||
fn get_sidewalk_width(attribs: &BTreeMap<String, String>) -> Option<si::Meter<f64>> {
|
||||
let meters_per_inch = 0.0254;
|
||||
fn get_sidewalk_width(attribs: &BTreeMap<String, String>) -> Option<Distance> {
|
||||
let base_width = attribs
|
||||
.get("SW_WIDTH")
|
||||
.and_then(|s| s.parse::<f64>().ok())
|
||||
.map(|inches| inches * meters_per_inch * si::M)?;
|
||||
.map(|i| Distance::inches(i))?;
|
||||
let filler_width = attribs
|
||||
.get("FILLERWID")
|
||||
.and_then(|s| s.parse::<f64>().ok())
|
||||
.map(|inches| inches * meters_per_inch * si::M)?;
|
||||
.map(|i| Distance::inches(i))?;
|
||||
Some(base_width + filler_width)
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::render::{DrawCrosswalk, DrawTurn, RenderOptions, Renderable, MIN_ZOOM_FOR_MARKINGS};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender, ScreenPt, Text};
|
||||
use geom::{Bounds, Circle, Line, Polygon, Pt2D};
|
||||
use geom::{Bounds, Circle, Distance, Duration, Line, Polygon, Pt2D};
|
||||
use map_model::{
|
||||
Cycle, Intersection, IntersectionID, IntersectionType, Map, TurnPriority, TurnType,
|
||||
LANE_THICKNESS,
|
||||
@ -225,7 +224,7 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
|
||||
};
|
||||
}
|
||||
|
||||
let radius = LANE_THICKNESS / 2.0 * si::M;
|
||||
let radius = Distance::meters(LANE_THICKNESS / 2.0);
|
||||
|
||||
// TODO Ignore right_ok...
|
||||
{
|
||||
@ -235,7 +234,7 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
|
||||
} else {
|
||||
ctx.cs.get_def("traffic light stop", Color::RED)
|
||||
};
|
||||
g.draw_circle(color, &Circle::new(center1, radius.value_unsafe));
|
||||
g.draw_circle(color, &Circle::new(center1, radius.inner_meters()));
|
||||
}
|
||||
|
||||
if let Some(pri) = left_priority {
|
||||
@ -249,14 +248,16 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
|
||||
};
|
||||
g.draw_circle(
|
||||
ctx.cs.get_def("traffic light box", Color::BLACK),
|
||||
&Circle::new(center2, radius.value_unsafe),
|
||||
&Circle::new(center2, radius.inner_meters()),
|
||||
);
|
||||
g.draw_arrow(
|
||||
color,
|
||||
0.1,
|
||||
&Line::new(
|
||||
center2.project_away(radius.value_unsafe, lane_line.angle().rotate_degs(90.0)),
|
||||
center2.project_away(radius.value_unsafe, lane_line.angle().rotate_degs(-90.0)),
|
||||
center2
|
||||
.project_away(radius.inner_meters(), lane_line.angle().rotate_degs(90.0)),
|
||||
center2
|
||||
.project_away(radius.inner_meters(), lane_line.angle().rotate_degs(-90.0)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -266,7 +267,7 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
|
||||
pub fn draw_signal_diagram(
|
||||
i: IntersectionID,
|
||||
current_cycle: usize,
|
||||
time_left: Option<si::Second<f64>>,
|
||||
time_left: Option<Duration>,
|
||||
y1_screen: f64,
|
||||
g: &mut GfxCtx,
|
||||
ctx: &Ctx,
|
||||
@ -289,7 +290,7 @@ pub fn draw_signal_diagram(
|
||||
for (idx, cycle) in cycles.iter().enumerate() {
|
||||
if idx == current_cycle && time_left.is_some() {
|
||||
// TODO Hacky way of indicating overtime
|
||||
if time_left.unwrap() < 0.0 * si::S {
|
||||
if time_left.unwrap() < Duration::ZERO {
|
||||
let mut txt = Text::from_line(format!("Cycle {}: ", idx + 1));
|
||||
txt.append(
|
||||
"OVERTIME".to_string(),
|
||||
@ -300,7 +301,7 @@ pub fn draw_signal_diagram(
|
||||
labels.push(Text::from_line(format!(
|
||||
"Cycle {}: {:.01}s / {}",
|
||||
idx + 1,
|
||||
(cycle.duration - time_left.unwrap()).value_unsafe,
|
||||
(cycle.duration - time_left.unwrap()).inner_seconds(),
|
||||
cycle.duration
|
||||
)));
|
||||
}
|
||||
@ -364,13 +365,13 @@ pub fn draw_signal_diagram(
|
||||
fn find_pts_between(pts: &Vec<Pt2D>, start: Pt2D, end: Pt2D) -> Option<Vec<Pt2D>> {
|
||||
let mut result = Vec::new();
|
||||
for pt in pts {
|
||||
if result.is_empty() && pt.approx_eq(start, 1.0 * si::M) {
|
||||
if result.is_empty() && pt.approx_eq(start, Distance::meters(1.0)) {
|
||||
result.push(*pt);
|
||||
} else if !result.is_empty() {
|
||||
result.push(*pt);
|
||||
}
|
||||
// start and end might be the same.
|
||||
if !result.is_empty() && pt.approx_eq(end, 1.0 * si::M) {
|
||||
if !result.is_empty() && pt.approx_eq(end, Distance::meters(1.0)) {
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
@ -383,7 +384,7 @@ fn find_pts_between(pts: &Vec<Pt2D>, start: Pt2D, end: Pt2D) -> Option<Vec<Pt2D>
|
||||
// Go through again, looking for end
|
||||
for pt in pts {
|
||||
result.push(*pt);
|
||||
if pt.approx_eq(end, 1.0 * si::M) {
|
||||
if pt.approx_eq(end, Distance::meters(1.0)) {
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@ use crate::render::{
|
||||
RenderOptions, Renderable, BIG_ARROW_THICKNESS, MIN_ZOOM_FOR_MARKINGS,
|
||||
PARCEL_BOUNDARY_THICKNESS,
|
||||
};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||
use geom::{Bounds, Circle, Line, Polygon, Pt2D};
|
||||
use geom::{Bounds, Circle, Distance, Line, Polygon, Pt2D};
|
||||
use map_model::{
|
||||
IntersectionType, Lane, LaneID, LaneType, Map, Road, Turn, LANE_THICKNESS, PARKING_SPOT_LENGTH,
|
||||
};
|
||||
@ -130,7 +129,7 @@ fn perp_line(l: Line, length: f64) -> Line {
|
||||
}
|
||||
|
||||
fn calculate_sidewalk_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon)> {
|
||||
let tile_every = LANE_THICKNESS * si::M;
|
||||
let tile_every = Distance::meters(LANE_THICKNESS);
|
||||
let color = cs.get_def("sidewalk lines", Color::grey(0.7));
|
||||
|
||||
let length = lane.length();
|
||||
@ -188,11 +187,11 @@ fn calculate_driving_lines(lane: &Lane, parent: &Road, cs: &ColorScheme) -> Vec<
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let dash_separation = 1.5 * si::M;
|
||||
let dash_len = 1.0 * si::M;
|
||||
let dash_separation = Distance::meters(1.5);
|
||||
let dash_len = Distance::meters(1.0);
|
||||
|
||||
let lane_edge_pts = lane.lane_center_pts.shift_left(LANE_THICKNESS / 2.0);
|
||||
if lane_edge_pts.length() < 2.0 * dash_separation {
|
||||
if lane_edge_pts.length() < dash_separation * 2.0 {
|
||||
return Vec::new();
|
||||
}
|
||||
// Don't draw the dashes too close to the ends.
|
||||
@ -219,7 +218,7 @@ fn calculate_stop_sign_line(
|
||||
|
||||
// TODO maybe draw the stop sign octagon on each lane?
|
||||
|
||||
let (pt1, angle) = lane.safe_dist_along(lane.length() - (1.0 * si::M))?;
|
||||
let (pt1, angle) = lane.safe_dist_along(lane.length() - Distance::meters(1.0))?;
|
||||
// Reuse perp_line. Project away an arbitrary amount
|
||||
let pt2 = pt1.project_away(1.0, angle);
|
||||
// Don't clobber the yellow line.
|
||||
@ -258,13 +257,13 @@ fn calculate_turn_markings(map: &Map, lane: &Lane, cs: &ColorScheme) -> Vec<(Col
|
||||
fn turn_markings(turn: &Turn, map: &Map, cs: &ColorScheme) -> Vec<(Color, Polygon)> {
|
||||
let lane = map.get_l(turn.id.src);
|
||||
let len = lane.length();
|
||||
if len < 7.0 * si::M {
|
||||
if len < Distance::meters(7.0) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let common_base = lane
|
||||
.lane_center_pts
|
||||
.slice(len - 7.0 * si::M, len - 5.0 * si::M)
|
||||
.slice(len - Distance::meters(7.0), len - Distance::meters(5.0))
|
||||
.unwrap()
|
||||
.0;
|
||||
let base_polygon = common_base.make_polygons(0.1);
|
||||
|
@ -3,9 +3,8 @@ use crate::render::{
|
||||
RenderOptions, Renderable, BIG_ARROW_THICKNESS, CROSSWALK_LINE_THICKNESS,
|
||||
TURN_ICON_ARROW_LENGTH, TURN_ICON_ARROW_THICKNESS,
|
||||
};
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Bounds, Circle, Line, Polygon, Pt2D};
|
||||
use geom::{Bounds, Circle, Distance, Line, Polygon, Pt2D};
|
||||
use map_model::{Map, Turn, TurnID, LANE_THICKNESS};
|
||||
use std::f64;
|
||||
|
||||
@ -23,9 +22,9 @@ impl DrawTurn {
|
||||
|
||||
let end_line = map.get_l(turn.id.src).end_line(turn.id.parent);
|
||||
// Start the distance from the intersection
|
||||
let icon_center = end_line
|
||||
.reverse()
|
||||
.unbounded_dist_along((offset_along_lane + 0.5) * TURN_ICON_ARROW_LENGTH * si::M);
|
||||
let icon_center = end_line.reverse().unbounded_dist_along(Distance::meters(
|
||||
(offset_along_lane + 0.5) * TURN_ICON_ARROW_LENGTH,
|
||||
));
|
||||
|
||||
let icon_circle = Circle::new(icon_center, TURN_ICON_ARROW_LENGTH / 2.0);
|
||||
|
||||
@ -51,10 +50,10 @@ impl DrawTurn {
|
||||
}
|
||||
|
||||
pub fn draw_dashed(turn: &Turn, g: &mut GfxCtx, color: Color) {
|
||||
let dash_len = 1.0 * si::M;
|
||||
let dashed = turn
|
||||
.geom
|
||||
.dashed_polygons(BIG_ARROW_THICKNESS, dash_len, 0.5 * si::M);
|
||||
let dash_len = Distance::meters(1.0);
|
||||
let dashed =
|
||||
turn.geom
|
||||
.dashed_polygons(BIG_ARROW_THICKNESS, dash_len, Distance::meters(0.5));
|
||||
g.draw_polygon_batch(dashed.iter().map(|poly| (color, poly)).collect());
|
||||
// And a cap on the arrow. In case the last line is long, trim it to be the dash
|
||||
// length.
|
||||
@ -119,8 +118,8 @@ impl DrawCrosswalk {
|
||||
// Start at least LANE_THICKNESS out to not hit sidewalk corners. Also account for
|
||||
// the thickness of the crosswalk line itself. Center the lines inside these two
|
||||
// boundaries.
|
||||
let boundary = (LANE_THICKNESS + CROSSWALK_LINE_THICKNESS) * si::M;
|
||||
let tile_every = 0.6 * LANE_THICKNESS * si::M;
|
||||
let boundary = Distance::meters(LANE_THICKNESS + CROSSWALK_LINE_THICKNESS);
|
||||
let tile_every = Distance::meters(0.6 * LANE_THICKNESS);
|
||||
let line = {
|
||||
// The middle line in the crosswalk geometry is the main crossing line.
|
||||
let pts = turn.geom.points();
|
||||
@ -128,8 +127,8 @@ impl DrawCrosswalk {
|
||||
};
|
||||
|
||||
let mut draw = Vec::new();
|
||||
let available_length = line.length() - (2.0 * boundary);
|
||||
if available_length > 0.0 * si::M {
|
||||
let available_length = line.length() - (boundary * 2.0);
|
||||
if available_length > Distance::ZERO {
|
||||
let num_markings = (available_length / tile_every).floor() as usize;
|
||||
let mut dist_along =
|
||||
boundary + (available_length - tile_every * (num_markings as f64)) / 2.0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use ordered_float::NotNan;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{fmt, ops};
|
||||
use std::{f64, fmt, ops};
|
||||
|
||||
// In meters. Can be negative.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
@ -8,6 +8,7 @@ pub struct Distance(f64);
|
||||
|
||||
impl Distance {
|
||||
pub const ZERO: Distance = Distance::const_meters(0.0);
|
||||
pub const MAX: Distance = Distance::const_meters(f64::MAX);
|
||||
|
||||
pub fn meters(value: f64) -> Distance {
|
||||
if !value.is_finite() {
|
||||
@ -22,6 +23,10 @@ impl Distance {
|
||||
Distance(value)
|
||||
}
|
||||
|
||||
pub fn inches(value: f64) -> Distance {
|
||||
Distance::meters(0.0254 * value)
|
||||
}
|
||||
|
||||
pub fn abs(self) -> Distance {
|
||||
if self.0 > 0.0 {
|
||||
self
|
||||
@ -107,10 +112,13 @@ impl ops::Div<f64> for Distance {
|
||||
}
|
||||
|
||||
// In seconds. Can be negative.
|
||||
// TODO Naming is awkward. Can represent a moment in time or a duration.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Duration(f64);
|
||||
|
||||
impl Duration {
|
||||
pub const ZERO: Duration = Duration::const_seconds(0.0);
|
||||
|
||||
pub fn seconds(value: f64) -> Duration {
|
||||
if !value.is_finite() {
|
||||
panic!("Bad Duration {}", value);
|
||||
@ -122,6 +130,19 @@ impl Duration {
|
||||
pub const fn const_seconds(value: f64) -> Duration {
|
||||
Duration(value)
|
||||
}
|
||||
|
||||
pub fn min(self, other: Duration) -> Duration {
|
||||
if self <= other {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove if possible.
|
||||
pub fn inner_seconds(self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Duration {
|
||||
@ -146,6 +167,14 @@ impl ops::Mul<f64> for Duration {
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Speed> for Duration {
|
||||
type Output = Distance;
|
||||
|
||||
fn mul(self, other: Speed) -> Distance {
|
||||
Distance::meters(self.0 * other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<Duration> for Duration {
|
||||
type Output = f64;
|
||||
|
||||
@ -162,6 +191,8 @@ impl ops::Div<Duration> for Duration {
|
||||
pub struct Speed(f64);
|
||||
|
||||
impl Speed {
|
||||
pub const ZERO: Speed = Speed::const_meters_per_second(0.0);
|
||||
|
||||
pub fn meters_per_second(value: f64) -> Speed {
|
||||
if !value.is_finite() {
|
||||
panic!("Bad Speed {}", value);
|
||||
@ -170,9 +201,72 @@ impl Speed {
|
||||
Speed(value)
|
||||
}
|
||||
|
||||
pub const fn const_meters_per_second(value: f64) -> Speed {
|
||||
Speed(value)
|
||||
}
|
||||
|
||||
pub fn miles_per_hour(value: f64) -> Speed {
|
||||
Speed::meters_per_second(0.44704 * value)
|
||||
}
|
||||
|
||||
// TODO Remove if possible.
|
||||
pub fn inner_meters_per_second(self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add for Speed {
|
||||
type Output = Speed;
|
||||
|
||||
fn add(self, other: Speed) -> Speed {
|
||||
Speed::meters_per_second(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Speed {
|
||||
type Output = Speed;
|
||||
|
||||
fn sub(self, other: Speed) -> Speed {
|
||||
Speed::meters_per_second(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<f64> for Speed {
|
||||
type Output = Speed;
|
||||
|
||||
fn mul(self, scalar: f64) -> Speed {
|
||||
Speed::meters_per_second(self.0 * scalar)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Duration> for Speed {
|
||||
type Output = Distance;
|
||||
|
||||
fn mul(self, other: Duration) -> Distance {
|
||||
Distance::meters(self.0 * other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<Duration> for Speed {
|
||||
type Output = Acceleration;
|
||||
|
||||
fn div(self, other: Duration) -> Acceleration {
|
||||
if other == Duration::ZERO {
|
||||
panic!("Can't divide {} / {}", self, other);
|
||||
}
|
||||
Acceleration::meters_per_second_squared(self.0 / other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<Acceleration> for Speed {
|
||||
type Output = Duration;
|
||||
|
||||
fn div(self, other: Acceleration) -> Duration {
|
||||
if other == Acceleration::ZERO {
|
||||
panic!("Can't divide {} / {}", self, other);
|
||||
}
|
||||
Duration::seconds(self.0 / other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Speed {
|
||||
@ -186,6 +280,8 @@ impl fmt::Display for Speed {
|
||||
pub struct Acceleration(f64);
|
||||
|
||||
impl Acceleration {
|
||||
pub const ZERO: Acceleration = Acceleration::const_meters_per_second_squared(0.0);
|
||||
|
||||
pub fn meters_per_second_squared(value: f64) -> Acceleration {
|
||||
if !value.is_finite() {
|
||||
panic!("Bad Acceleration {}", value);
|
||||
@ -193,6 +289,28 @@ impl Acceleration {
|
||||
|
||||
Acceleration(value)
|
||||
}
|
||||
|
||||
pub const fn const_meters_per_second_squared(value: f64) -> Acceleration {
|
||||
Acceleration(value)
|
||||
}
|
||||
|
||||
// TODO Remove by making Acceleration itself Ord.
|
||||
pub fn as_ordered(self) -> NotNan<f64> {
|
||||
NotNan::new(self.0).unwrap()
|
||||
}
|
||||
|
||||
pub fn min(self, other: Acceleration) -> Acceleration {
|
||||
if self <= other {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove if possible.
|
||||
pub fn inner_meters_per_second_squared(self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Acceleration {
|
||||
@ -200,3 +318,11 @@ impl fmt::Display for Acceleration {
|
||||
write!(f, "{}m/s^2", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<Duration> for Acceleration {
|
||||
type Output = Speed;
|
||||
|
||||
fn mul(self, other: Duration) -> Speed {
|
||||
Speed::meters_per_second(self.0 * other.0)
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,12 @@ edition = "2018"
|
||||
abstutil = { path = "../abstutil" }
|
||||
backtrace = "0.3.9"
|
||||
derivative = "1.0.0"
|
||||
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
|
||||
geom = { path = "../geom" }
|
||||
lazy_static = "1.1.0"
|
||||
log = "0.4.5"
|
||||
map_model = { path = "../map_model" }
|
||||
more-asserts = "0.2.1"
|
||||
multimap = "0.4.0"
|
||||
ordered-float = "1.0.1"
|
||||
pretty_assertions = "0.5.1"
|
||||
rand = { version = "0.6.4", features = ["serde1"] }
|
||||
rand_xorshift = "0.1.1"
|
||||
|
@ -6,28 +6,22 @@ use crate::router::Router;
|
||||
use crate::transit::TransitSimState;
|
||||
use crate::view::{AgentView, WorldView};
|
||||
use crate::{
|
||||
Acceleration, AgentID, CarID, CarState, Distance, DrawCarInput, Event, ParkedCar, ParkingSpot,
|
||||
Speed, Tick, Time, TripID, VehicleType,
|
||||
AgentID, CarID, CarState, DrawCarInput, Event, ParkedCar, ParkingSpot, Tick, TripID,
|
||||
VehicleType,
|
||||
};
|
||||
use abstutil;
|
||||
use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
|
||||
use dimensioned::si;
|
||||
use geom::EPSILON_DIST;
|
||||
use geom::{Acceleration, Distance, Duration, Speed, EPSILON_DIST};
|
||||
use map_model::{
|
||||
BuildingID, IntersectionID, LaneID, Map, Path, PathStep, Position, Trace, Traversable, TurnID,
|
||||
LANE_THICKNESS,
|
||||
};
|
||||
use multimap::MultiMap;
|
||||
use ordered_float::NotNan;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
const TIME_TO_PARK_OR_DEPART: Time = si::Second {
|
||||
value_unsafe: 10.0,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const TIME_TO_PARK_OR_DEPART: Duration = Duration::const_seconds(10.0);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum DrivingGoal {
|
||||
@ -121,7 +115,7 @@ impl Car {
|
||||
let mut current_on = self.on;
|
||||
let mut current_dist_along = self.dist_along;
|
||||
let mut current_router = orig_router.clone();
|
||||
let mut dist_scanned_ahead = 0.0 * si::M;
|
||||
let mut dist_scanned_ahead = Distance::ZERO;
|
||||
|
||||
if self.debug {
|
||||
debug!(
|
||||
@ -198,7 +192,7 @@ impl Car {
|
||||
let dist_to_maybe_stop_at =
|
||||
maybe_stop_early.unwrap_or_else(|| current_on.length(map));
|
||||
let dist_from_stop = dist_to_maybe_stop_at - current_dist_along;
|
||||
if dist_from_stop < 0.0 * si::M {
|
||||
if dist_from_stop < Distance::ZERO {
|
||||
return Err(Error::new(format!("Router for {} looking ahead to {:?} said to stop at {:?}, but lookahead already at {}", self.id, current_on, maybe_stop_early, current_dist_along)));
|
||||
}
|
||||
|
||||
@ -245,20 +239,19 @@ impl Car {
|
||||
// Advance to the next step.
|
||||
let dist_this_step = current_on.length(map) - current_dist_along;
|
||||
dist_to_lookahead -= dist_this_step;
|
||||
if dist_to_lookahead <= 0.0 * si::M {
|
||||
if dist_to_lookahead <= Distance::ZERO {
|
||||
break;
|
||||
}
|
||||
current_on = current_router.finished_step(current_on).as_traversable();
|
||||
current_dist_along = 0.0 * si::M;
|
||||
current_dist_along = Distance::ZERO;
|
||||
dist_scanned_ahead += dist_this_step;
|
||||
}
|
||||
|
||||
// Clamp based on what we can actually do
|
||||
// TODO this type mangling is awful
|
||||
let safe_accel = vehicle.clamp_accel(
|
||||
constraints
|
||||
.into_iter()
|
||||
.min_by_key(|a| NotNan::new(a.value_unsafe).unwrap())
|
||||
.min_by_key(|a| a.as_ordered())
|
||||
.unwrap(),
|
||||
);
|
||||
if self.debug {
|
||||
@ -306,7 +299,7 @@ impl Car {
|
||||
}
|
||||
|
||||
let leftover_dist = self.dist_along - self.on.length(map);
|
||||
if leftover_dist < 0.0 * si::M {
|
||||
if leftover_dist < Distance::ZERO {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -384,7 +377,7 @@ impl SimQueue {
|
||||
let mut cars_queue: Vec<(Distance, CarID)> =
|
||||
ids.iter().map(|id| (cars[id].dist_along, *id)).collect();
|
||||
// Sort descending.
|
||||
cars_queue.sort_by_key(|(dist, _)| -NotNan::new(dist.value_unsafe).unwrap());
|
||||
cars_queue.sort_by_key(|(dist, _)| -dist.as_ordered());
|
||||
|
||||
let capacity =
|
||||
((id.length(map) / Vehicle::best_case_following_dist()).ceil() as usize).max(1);
|
||||
@ -425,7 +418,7 @@ impl SimQueue {
|
||||
adjusted_cars += 1;
|
||||
|
||||
let fixed_dist = dist2 - (kinematics::FOLLOWING_DISTANCE - dist_apart);
|
||||
if fixed_dist < 0.0 * si::M {
|
||||
if fixed_dist < Distance::ZERO {
|
||||
return Err(Error::new(format!("can't hack around bug where cars are too close on {:?}, because last car doesn't have room to be shifted back", id)));
|
||||
}
|
||||
cars.get_mut(&c2).unwrap().dist_along = fixed_dist;
|
||||
@ -691,7 +684,7 @@ impl DrivingSimState {
|
||||
let mut cars_per_traversable = MultiMap::new();
|
||||
for c in self.cars.values() {
|
||||
// Also do some sanity checks.
|
||||
if c.dist_along < 0.0 * si::M {
|
||||
if c.dist_along < Distance::ZERO {
|
||||
return Err(Error::new(format!(
|
||||
"{} is {} along {:?}",
|
||||
c.id, c.dist_along, c.on
|
||||
@ -757,7 +750,7 @@ impl DrivingSimState {
|
||||
other_vehicle.clamp_speed(map.get_parent(start_lane).get_speed_limit()),
|
||||
¶ms.vehicle,
|
||||
start_dist - other_dist - params.vehicle.length,
|
||||
0.0 * si::MPS,
|
||||
Speed::ZERO,
|
||||
)
|
||||
.unwrap();
|
||||
if accel_for_other_to_stop <= other_vehicle.max_deaccel {
|
||||
@ -778,7 +771,7 @@ impl DrivingSimState {
|
||||
owner: params.owner,
|
||||
on: start_on,
|
||||
dist_along: start_dist,
|
||||
speed: 0.0 * si::MPS,
|
||||
speed: Speed::ZERO,
|
||||
vehicle: params.vehicle,
|
||||
debug: false,
|
||||
parking: params.maybe_parked_car.and_then(|parked_car| {
|
||||
@ -846,7 +839,7 @@ impl DrivingSimState {
|
||||
prev_len - prev_dist
|
||||
} else {
|
||||
// TODO we need two steps back, urgh
|
||||
0.0 * si::M
|
||||
Distance::ZERO
|
||||
},
|
||||
c.vehicle.length,
|
||||
)
|
||||
@ -854,12 +847,11 @@ impl DrivingSimState {
|
||||
} else {
|
||||
// TODO Kinda weird to consider the car not present, but eventually cars spawning
|
||||
// at borders should appear fully anyway.
|
||||
c.on.slice(0.0 * si::M, c.dist_along, map)?.0
|
||||
c.on.slice(Distance::ZERO, c.dist_along, map)?.0
|
||||
};
|
||||
|
||||
let body = if let Some(ref parking) = c.parking {
|
||||
let progress: f64 =
|
||||
((time - parking.started_at).as_time() / TIME_TO_PARK_OR_DEPART).value_unsafe;
|
||||
let progress: f64 = (time - parking.started_at).as_time() / TIME_TO_PARK_OR_DEPART;
|
||||
assert!(progress >= 0.0 && progress <= 1.0);
|
||||
let project_away_ratio = if parking.is_parking {
|
||||
progress
|
||||
|
@ -1,7 +1,6 @@
|
||||
use dimensioned::si;
|
||||
use geom::Pt2D;
|
||||
use geom::{Duration, Speed, Distance, Pt2D};
|
||||
use map_model::{BuildingID, BusRouteID, BusStopID, LaneID, Map, TurnID};
|
||||
use crate::{CarID, Distance, ParkingSpot, Time};
|
||||
use crate::{CarID, ParkingSpot};
|
||||
|
||||
// This is experimental for now, but it might subsume the entire design of the sim crate.
|
||||
|
||||
@ -39,10 +38,10 @@ enum Action {
|
||||
|
||||
impl Action {
|
||||
// These are always lower bounds, aka, the best case.
|
||||
fn cost(&self, map: &Map) -> Time {
|
||||
fn cost(&self, map: &Map) -> Duration {
|
||||
// TODO driving speed limits and these could depend on preferences of the individual
|
||||
// ped/vehicle
|
||||
let ped_speed = 3.9 * si::MPS;
|
||||
let ped_speed = Speed::meters_per_second(3.9);
|
||||
|
||||
match *self {
|
||||
// TODO wait, we need to know if a ped or car is crossing something
|
||||
@ -50,17 +49,17 @@ impl Action {
|
||||
Action::CrossTurn(id) => {
|
||||
map.get_t(id).length() / map.get_parent(id.dst).get_speed_limit()
|
||||
}
|
||||
Action::ParkingCar(_, _) => 20.0 * si::S,
|
||||
Action::UnparkingCar(_, _) => 10.0 * si::S,
|
||||
Action::ParkingCar(_, _) => Duration::seconds(20.0),
|
||||
Action::UnparkingCar(_, _) => Duration::seconds(10.0),
|
||||
Action::CrossLaneContraflow(id) => map.get_l(id).length() / ped_speed,
|
||||
Action::CrossPathFromBuildingToSidewalk(id)
|
||||
| Action::CrossPathFromSidewalkToBuilding(id) => {
|
||||
map.get_b(id).front_path.line.length() / ped_speed
|
||||
}
|
||||
// TODO Could try lots of things here...
|
||||
Action::WaitForBus(_, _) => 60.0 * si::S,
|
||||
Action::WaitForBus(_, _) => Duration::seconds(60.0),
|
||||
// TODO Cache the expected time to travel between stops
|
||||
Action::RideBus(_stop1, _stop2) => 300.0 * si::S,
|
||||
Action::RideBus(_stop1, _stop2) => Duration::seconds(300.0),
|
||||
|
||||
_ => panic!("TODO"),
|
||||
}
|
||||
@ -71,7 +70,7 @@ impl Action {
|
||||
// TODO hard to convert distance and time
|
||||
fn heuristic(&self, goal: Pt2D) -> Distance {
|
||||
// TODO
|
||||
0.0 * si::M
|
||||
Distance::ZERO
|
||||
}
|
||||
|
||||
fn next_steps(&self) -> Vec<Action> {
|
||||
|
@ -1,18 +1,14 @@
|
||||
use crate::kinematics;
|
||||
use crate::view::WorldView;
|
||||
use crate::{AgentID, CarID, Event, PedestrianID, Tick, Time};
|
||||
use crate::{AgentID, CarID, Event, PedestrianID, Tick};
|
||||
use abstutil;
|
||||
use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
|
||||
use dimensioned::si;
|
||||
use geom::Duration;
|
||||
use map_model::{ControlStopSign, IntersectionID, IntersectionType, Map, TurnID, TurnPriority};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
||||
|
||||
const WAIT_AT_STOP_SIGN: Time = si::Second {
|
||||
value_unsafe: 1.5,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const WAIT_AT_STOP_SIGN: Duration = Duration::const_seconds(1.5);
|
||||
|
||||
// One agent may make several requests at one intersection at a time. This is normal for
|
||||
// pedestrians and crosswalks. IntersectionPolicies should expect this.
|
||||
|
@ -1,48 +1,25 @@
|
||||
use crate::{Acceleration, CarID, Distance, Speed, Time, TIMESTEP};
|
||||
use crate::{CarID, TIMESTEP};
|
||||
use abstutil::Error;
|
||||
use dimensioned::si;
|
||||
use geom::EPSILON_DIST;
|
||||
use geom::{Acceleration, Distance, Duration, Speed, EPSILON_DIST};
|
||||
use more_asserts::assert_ge;
|
||||
use rand::Rng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std;
|
||||
|
||||
pub const EPSILON_SPEED: Speed = si::MeterPerSecond {
|
||||
value_unsafe: 0.000_000_01,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
pub const EPSILON_SPEED: Speed = Speed::const_meters_per_second(0.000_000_01);
|
||||
|
||||
// http://pccsc.net/bicycle-parking-info/ says 68 inches, which is 1.73m
|
||||
const MIN_BIKE_LENGTH: Distance = si::Meter {
|
||||
value_unsafe: 1.7,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const MAX_BIKE_LENGTH: Distance = si::Meter {
|
||||
value_unsafe: 2.0,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const MIN_BIKE_LENGTH: Distance = Distance::const_meters(1.7);
|
||||
const MAX_BIKE_LENGTH: Distance = Distance::const_meters(2.0);
|
||||
// These two must be < PARKING_SPOT_LENGTH
|
||||
pub const MIN_CAR_LENGTH: Distance = si::Meter {
|
||||
value_unsafe: 4.5,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const MAX_CAR_LENGTH: Distance = si::Meter {
|
||||
value_unsafe: 6.5,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
pub const MIN_CAR_LENGTH: Distance = Distance::const_meters(4.5);
|
||||
const MAX_CAR_LENGTH: Distance = Distance::const_meters(6.5);
|
||||
// Note this is more than MAX_CAR_LENGTH
|
||||
const BUS_LENGTH: Distance = si::Meter {
|
||||
value_unsafe: 12.5,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const BUS_LENGTH: Distance = Distance::const_meters(12.5);
|
||||
|
||||
// At all speeds (including at rest), cars must be at least this far apart, measured from front of
|
||||
// one car to the back of the other.
|
||||
pub const FOLLOWING_DISTANCE: Distance = si::Meter {
|
||||
value_unsafe: 1.0,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
pub const FOLLOWING_DISTANCE: Distance = Distance::const_meters(1.0);
|
||||
|
||||
// TODO unit test all of this
|
||||
// TODO handle floating point issues uniformly here
|
||||
@ -75,10 +52,12 @@ impl Vehicle {
|
||||
id,
|
||||
vehicle_type: VehicleType::Car,
|
||||
debug: false,
|
||||
max_accel: rng.gen_range(2.4, 2.8) * si::MPS2,
|
||||
max_deaccel: rng.gen_range(-2.8, -2.4) * si::MPS2,
|
||||
max_accel: Acceleration::meters_per_second_squared(rng.gen_range(2.4, 2.8)),
|
||||
max_deaccel: Acceleration::meters_per_second_squared(rng.gen_range(-2.8, -2.4)),
|
||||
// TODO more realistic to have a few preset lengths and choose between them
|
||||
length: rng.gen_range(MIN_CAR_LENGTH.value_unsafe, MAX_CAR_LENGTH.value_unsafe) * si::M,
|
||||
length: Distance::meters(
|
||||
rng.gen_range(MIN_CAR_LENGTH.inner_meters(), MAX_CAR_LENGTH.inner_meters()),
|
||||
),
|
||||
max_speed: None,
|
||||
}
|
||||
}
|
||||
@ -88,8 +67,8 @@ impl Vehicle {
|
||||
id,
|
||||
vehicle_type: VehicleType::Bus,
|
||||
debug: false,
|
||||
max_accel: rng.gen_range(2.4, 2.8) * si::MPS2,
|
||||
max_deaccel: rng.gen_range(-2.8, -2.4) * si::MPS2,
|
||||
max_accel: Acceleration::meters_per_second_squared(rng.gen_range(2.4, 2.8)),
|
||||
max_deaccel: Acceleration::meters_per_second_squared(rng.gen_range(-2.8, -2.4)),
|
||||
length: BUS_LENGTH,
|
||||
max_speed: None,
|
||||
}
|
||||
@ -101,14 +80,16 @@ impl Vehicle {
|
||||
vehicle_type: VehicleType::Bike,
|
||||
debug: false,
|
||||
// http://eprints.uwe.ac.uk/20767/ says mean 0.231
|
||||
max_accel: rng.gen_range(0.2, 0.3) * si::MPS2,
|
||||
max_accel: Acceleration::meters_per_second_squared(rng.gen_range(0.2, 0.3)),
|
||||
// Much easier deaccel. Partly to avoid accel_to_stop_in_dist bugs with bikes running
|
||||
// stop signs.
|
||||
max_deaccel: rng.gen_range(-1.3, -1.2) * si::MPS2,
|
||||
length: rng.gen_range(MIN_BIKE_LENGTH.value_unsafe, MAX_BIKE_LENGTH.value_unsafe)
|
||||
* si::M,
|
||||
max_deaccel: Acceleration::meters_per_second_squared(rng.gen_range(-1.3, -1.2)),
|
||||
length: Distance::meters(rng.gen_range(
|
||||
MIN_BIKE_LENGTH.inner_meters(),
|
||||
MAX_BIKE_LENGTH.inner_meters(),
|
||||
)),
|
||||
// 7 to 10 mph
|
||||
max_speed: Some(rng.gen_range(3.13, 4.47) * si::MPS),
|
||||
max_speed: Some(Speed::meters_per_second(rng.gen_range(3.13, 4.47))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +123,7 @@ impl Vehicle {
|
||||
|
||||
pub fn stopping_distance(&self, speed: Speed) -> Result<Distance, Error> {
|
||||
// 0 = v_0 + a*t
|
||||
let stopping_time = -1.0 * speed / self.max_deaccel;
|
||||
let stopping_time = speed / self.max_deaccel * -1.0;
|
||||
dist_at_constant_accel(self.max_deaccel, stopping_time, speed)
|
||||
}
|
||||
|
||||
@ -161,7 +142,7 @@ impl Vehicle {
|
||||
speed: Speed,
|
||||
dist: Distance,
|
||||
) -> Result<Acceleration, Error> {
|
||||
if dist < -EPSILON_DIST {
|
||||
if dist < EPSILON_DIST * -1.0 {
|
||||
return Err(Error::new(format!(
|
||||
"{} called accel_to_stop_in_dist({}, {}) with negative distance",
|
||||
self.id, speed, dist
|
||||
@ -170,9 +151,9 @@ impl Vehicle {
|
||||
|
||||
// Don't NaN out. Don't check for <= EPSILON_DIST here -- it makes cars slightly overshoot
|
||||
// sometimes.
|
||||
if dist <= 0.0 * si::M {
|
||||
if dist <= Distance::ZERO {
|
||||
// TODO assert speed is 0ish?
|
||||
return Ok(0.0 * si::MPS2);
|
||||
return Ok(Acceleration::ZERO);
|
||||
}
|
||||
|
||||
// d = (v_1)(t) + (1/2)(a)(t^2)
|
||||
@ -180,12 +161,16 @@ impl Vehicle {
|
||||
// Eliminating time yields the formula for accel below. This same accel should be applied
|
||||
// for t = -v_1 / a, which is possible even if that's not a multiple of TIMESTEP since
|
||||
// we're decelerating to rest.
|
||||
let normal_case: Acceleration = (-1.0 * speed * speed) / (2.0 * dist);
|
||||
let required_time: Time = -1.0 * speed / normal_case;
|
||||
let normal_case = Acceleration::meters_per_second_squared(
|
||||
(-1.0 * speed.inner_meters_per_second() * speed.inner_meters_per_second())
|
||||
/ (2.0 * dist.inner_meters()),
|
||||
);
|
||||
// TODO might validlyish be NaN, so just f64 here
|
||||
let required_time: f64 = (speed / normal_case * -1.0).inner_seconds();
|
||||
|
||||
if self.debug {
|
||||
debug!(
|
||||
" accel_to_stop_in_dist({}, {}) would normally recommend {} and take {} to finish",
|
||||
" accel_to_stop_in_dist({}, {}) would normally recommend {} and take {}s to finish",
|
||||
speed, dist, normal_case, required_time
|
||||
);
|
||||
}
|
||||
@ -194,7 +179,7 @@ impl Vehicle {
|
||||
// absurd amount of time to finish, with tiny little steps. But need to tune and understand
|
||||
// this value better. Higher initial speeds or slower max_deaccel's mean this is naturally
|
||||
// going to take longer. We don't want to start stopping now if we can't undo it next tick.
|
||||
if !required_time.value_unsafe.is_nan() && required_time < 15.0 * si::S {
|
||||
if !required_time.is_nan() && Duration::seconds(required_time) < Duration::seconds(15.0) {
|
||||
return Ok(normal_case);
|
||||
}
|
||||
|
||||
@ -203,7 +188,9 @@ impl Vehicle {
|
||||
// acceleration is then too high, we'll cap off and trigger a normal case next tick.
|
||||
// Want (1/2)(a)(dt^2) + (a dt)dt - (1/2)(a)(dt^2) = dist
|
||||
// TODO I don't understand the above.
|
||||
Ok(dist / (TIMESTEP * TIMESTEP))
|
||||
Ok(Acceleration::meters_per_second_squared(
|
||||
dist.inner_meters() / (TIMESTEP.inner_seconds() * TIMESTEP.inner_seconds()),
|
||||
))
|
||||
}
|
||||
|
||||
// Assume we accelerate as much as possible this tick (restricted only by the speed limit),
|
||||
@ -231,10 +218,9 @@ impl Vehicle {
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(min_accel(
|
||||
self.max_accel,
|
||||
self.accel_to_achieve_speed_in_one_tick(current_speed, speed_limit),
|
||||
))
|
||||
Ok(self
|
||||
.max_accel
|
||||
.min(self.accel_to_achieve_speed_in_one_tick(current_speed, speed_limit)))
|
||||
}
|
||||
|
||||
fn max_next_dist(&self, current_speed: Speed, speed_limit: Speed) -> Result<Distance, Error> {
|
||||
@ -274,10 +260,10 @@ impl Vehicle {
|
||||
|
||||
fn dist_at_constant_accel(
|
||||
accel: Acceleration,
|
||||
time: Time,
|
||||
time: Duration,
|
||||
initial_speed: Speed,
|
||||
) -> Result<Distance, Error> {
|
||||
if time < 0.0 * si::S {
|
||||
if time < Duration::ZERO {
|
||||
return Err(Error::new(format!(
|
||||
"dist_at_constant_accel called with time = {}",
|
||||
time
|
||||
@ -285,14 +271,18 @@ fn dist_at_constant_accel(
|
||||
}
|
||||
|
||||
// Don't deaccelerate into going backwards, just cap things off.
|
||||
let actual_time = if accel >= 0.0 * si::MPS2 {
|
||||
let actual_time = if accel >= Acceleration::ZERO {
|
||||
time
|
||||
} else {
|
||||
// 0 = v_0 + a*t
|
||||
min_time(time, -1.0 * initial_speed / accel)
|
||||
time.min(initial_speed / accel * -1.0)
|
||||
};
|
||||
let dist = (initial_speed * actual_time) + (0.5 * accel * (actual_time * actual_time));
|
||||
if dist < 0.0 * si::M {
|
||||
let dist = (initial_speed * actual_time)
|
||||
+ Distance::meters(
|
||||
0.5 * accel.inner_meters_per_second_squared()
|
||||
* (actual_time.inner_seconds() * actual_time.inner_seconds()),
|
||||
);
|
||||
if dist < Distance::ZERO {
|
||||
return Err(Error::new(format!(
|
||||
"dist_at_constant_accel yielded result = {}",
|
||||
dist
|
||||
@ -301,42 +291,35 @@ fn dist_at_constant_accel(
|
||||
Ok(dist)
|
||||
}
|
||||
|
||||
fn min_time(t1: Time, t2: Time) -> Time {
|
||||
if t1 < t2 {
|
||||
return t1;
|
||||
}
|
||||
t2
|
||||
}
|
||||
|
||||
fn min_accel(a1: Acceleration, a2: Acceleration) -> Acceleration {
|
||||
if a1 < a2 {
|
||||
return a1;
|
||||
}
|
||||
a2
|
||||
}
|
||||
|
||||
pub fn results_of_accel_for_one_tick(
|
||||
initial_speed: Speed,
|
||||
accel: Acceleration,
|
||||
) -> (Distance, Speed) {
|
||||
// Don't deaccelerate into going backwards, just cap things off.
|
||||
let actual_time = if accel >= 0.0 * si::MPS2 {
|
||||
let actual_time = if accel >= Acceleration::ZERO {
|
||||
TIMESTEP
|
||||
} else {
|
||||
min_time(TIMESTEP, -1.0 * initial_speed / accel)
|
||||
TIMESTEP.min(initial_speed / accel * -1.0)
|
||||
};
|
||||
let dist = (initial_speed * actual_time) + (0.5 * accel * (actual_time * actual_time));
|
||||
assert_ge!(dist, 0.0 * si::M);
|
||||
let dist = (initial_speed * actual_time)
|
||||
+ Distance::meters(
|
||||
0.5 * accel.inner_meters_per_second_squared()
|
||||
* (actual_time.inner_seconds() * actual_time.inner_seconds()),
|
||||
);
|
||||
assert_ge!(dist, Distance::ZERO);
|
||||
let mut new_speed = initial_speed + (accel * actual_time);
|
||||
// Handle some floating point imprecision
|
||||
if new_speed < 0.0 * si::MPS && new_speed >= -1.0 * EPSILON_SPEED {
|
||||
new_speed = 0.0 * si::MPS;
|
||||
if new_speed < Speed::ZERO && new_speed >= EPSILON_SPEED * -1.0 {
|
||||
new_speed = Speed::ZERO;
|
||||
}
|
||||
assert_ge!(new_speed, 0.0 * si::MPS);
|
||||
assert_ge!(new_speed, Speed::ZERO);
|
||||
(dist, new_speed)
|
||||
}
|
||||
|
||||
fn accel_to_cover_dist_in_one_tick(dist: Distance, speed: Speed) -> Acceleration {
|
||||
// d = (v_i)(t) + (1/2)(a)(t^2), solved for a
|
||||
2.0 * (dist - (speed * TIMESTEP)) / (TIMESTEP * TIMESTEP)
|
||||
Acceleration::meters_per_second_squared(
|
||||
2.0 * (dist - (speed * TIMESTEP)).inner_meters()
|
||||
/ (TIMESTEP.inner_seconds() * TIMESTEP.inner_seconds()),
|
||||
)
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ pub use crate::make::{
|
||||
load, ABTest, ABTestResults, BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars,
|
||||
SimFlags, SpawnOverTime,
|
||||
};
|
||||
pub use crate::physics::{Acceleration, Distance, Speed, Tick, Time, TIMESTEP};
|
||||
pub use crate::physics::{Tick, TIMESTEP};
|
||||
pub use crate::query::{Benchmark, ScoreSummary, SimStats, Summary};
|
||||
pub use crate::render::{CarState, DrawCarInput, DrawPedestrianInput, GetDrawAgents};
|
||||
pub use crate::sim::Sim;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::kinematics::Vehicle;
|
||||
use crate::{CarID, CarState, Distance, DrawCarInput, ParkedCar, ParkingSpot, VehicleType};
|
||||
use geom::{Angle, Pt2D};
|
||||
use crate::{CarID, CarState, DrawCarInput, ParkedCar, ParkingSpot, VehicleType};
|
||||
use geom::{Angle, Distance, Pt2D};
|
||||
use map_model;
|
||||
use map_model::{BuildingID, Lane, LaneID, LaneType, Map, Position, Traversable};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
@ -1,20 +1,11 @@
|
||||
use dimensioned::si;
|
||||
use geom::Duration;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::Rng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use regex::Regex;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
pub const TIMESTEP: Time = si::Second {
|
||||
value_unsafe: 0.1,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
// TODO Don't just alias types; assert that time, dist, and speed are always positive
|
||||
pub type Time = si::Second<f64>;
|
||||
pub type Distance = si::Meter<f64>;
|
||||
pub type Speed = si::MeterPerSecond<f64>;
|
||||
pub type Acceleration = si::MeterPerSecond2<f64>;
|
||||
pub const TIMESTEP: Duration = Duration::const_seconds(0.1);
|
||||
|
||||
// Represents a moment in time, not a duration/delta
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
@ -29,8 +20,8 @@ impl Tick {
|
||||
Tick(0)
|
||||
}
|
||||
|
||||
pub fn from_minutes(secs: u32) -> Tick {
|
||||
Tick(60 * 10 * secs)
|
||||
pub fn from_minutes(mins: u32) -> Tick {
|
||||
Tick(60 * 10 * mins)
|
||||
}
|
||||
|
||||
pub fn from_seconds(secs: u32) -> Tick {
|
||||
@ -88,8 +79,9 @@ impl Tick {
|
||||
Some(Tick(hours + minutes + seconds + ms))
|
||||
}
|
||||
|
||||
pub fn as_time(self) -> Time {
|
||||
f64::from(self.0) * TIMESTEP
|
||||
// TODO as_duration?
|
||||
pub fn as_time(self) -> Duration {
|
||||
TIMESTEP * f64::from(self.0)
|
||||
}
|
||||
|
||||
pub fn next(self) -> Tick {
|
||||
@ -135,11 +127,11 @@ impl Tick {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add<Time> for Tick {
|
||||
impl std::ops::Add<Duration> for Tick {
|
||||
type Output = Tick;
|
||||
|
||||
fn add(self, other: Time) -> Tick {
|
||||
let ticks = other.value_unsafe / TIMESTEP.value_unsafe;
|
||||
fn add(self, other: Duration) -> Tick {
|
||||
let ticks = other / TIMESTEP;
|
||||
// TODO check that there's no remainder!
|
||||
Tick(self.0 + (ticks as u32))
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Code to inspect the simulation state.
|
||||
|
||||
use crate::{Sim, Tick, TripID};
|
||||
use dimensioned::si;
|
||||
use geom::Pt2D;
|
||||
use map_model::LaneID;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@ -44,11 +43,11 @@ impl Sim {
|
||||
}
|
||||
|
||||
pub fn measure_speed(&self, b: &mut Benchmark) -> f64 {
|
||||
let dt = abstutil::elapsed_seconds(b.last_real_time) * si::S;
|
||||
let dt = geom::Duration::seconds(abstutil::elapsed_seconds(b.last_real_time));
|
||||
let speed = (self.time - b.last_sim_time).as_time() / dt;
|
||||
b.last_real_time = Instant::now();
|
||||
b.last_sim_time = self.time;
|
||||
speed.value_unsafe
|
||||
speed
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,8 @@ use crate::kinematics::Vehicle;
|
||||
use crate::parking::ParkingSimState;
|
||||
use crate::transit::TransitSimState;
|
||||
use crate::view::AgentView;
|
||||
use crate::{Distance, Event, ParkingSpot, Tick};
|
||||
use dimensioned::si;
|
||||
use geom::EPSILON_DIST;
|
||||
use crate::{Event, ParkingSpot, Tick};
|
||||
use geom::{Acceleration, Distance, EPSILON_DIST};
|
||||
use map_model::{
|
||||
BuildingID, LaneID, LaneType, Map, Path, PathStep, Position, Trace, Traversable, TurnID,
|
||||
};
|
||||
@ -115,7 +114,7 @@ impl Router {
|
||||
self.path = p;
|
||||
}
|
||||
if should_idle {
|
||||
return Some(Action::Continue(0.0 * si::MPS2, Vec::new()));
|
||||
return Some(Action::Continue(Acceleration::ZERO, Vec::new()));
|
||||
}
|
||||
}
|
||||
// Don't stop at the border node; plow through
|
||||
|
@ -8,12 +8,11 @@ use crate::transit::TransitSimState;
|
||||
use crate::trips::TripManager;
|
||||
use crate::view::WorldView;
|
||||
use crate::walking::WalkingSimState;
|
||||
use crate::{
|
||||
AgentID, CarID, Distance, Event, ParkedCar, PedestrianID, SimStats, Tick, TripID, TIMESTEP,
|
||||
};
|
||||
use crate::{AgentID, CarID, Event, ParkedCar, PedestrianID, SimStats, Tick, TripID, TIMESTEP};
|
||||
use abstutil;
|
||||
use abstutil::Error;
|
||||
use derivative::Derivative;
|
||||
use geom::Distance;
|
||||
use map_model::{BuildingID, IntersectionID, LaneID, LaneType, Map, Path, Trace, Turn};
|
||||
use rand::{FromEntropy, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
AgentID, CarID, Event, ParkedCar, ParkingSpot, PedestrianID, Tick, TripID, VehicleType,
|
||||
};
|
||||
use abstutil::{fork_rng, WeightedUsizeChoice};
|
||||
use dimensioned::si;
|
||||
use geom::Distance;
|
||||
use map_model::{
|
||||
BuildingID, BusRoute, BusRouteID, BusStopID, LaneID, LaneType, Map, Path, PathRequest,
|
||||
Pathfinder, Position, RoadID,
|
||||
@ -114,7 +114,7 @@ impl Command {
|
||||
DrivingGoal::Border(_, l) => *l,
|
||||
};
|
||||
PathRequest {
|
||||
start: Position::new(*start, 0.0 * si::M),
|
||||
start: Position::new(*start, Distance::ZERO),
|
||||
end: Position::new(goal_lane, map.get_l(goal_lane).length()),
|
||||
can_use_bus_lanes: vehicle.vehicle_type == VehicleType::Bus,
|
||||
can_use_bike_lanes: vehicle.vehicle_type == VehicleType::Bike,
|
||||
@ -222,7 +222,7 @@ impl Spawner {
|
||||
owner: None,
|
||||
maybe_parked_car: None,
|
||||
vehicle: vehicle.clone(),
|
||||
start: Position::new(start, 0.0 * si::M),
|
||||
start: Position::new(start, Distance::ZERO),
|
||||
router: match goal {
|
||||
DrivingGoal::ParkNear(b) => {
|
||||
if vehicle.vehicle_type == VehicleType::Bike {
|
||||
|
@ -4,9 +4,9 @@ use crate::spawn::Spawner;
|
||||
use crate::trips::TripManager;
|
||||
use crate::view::AgentView;
|
||||
use crate::walking::WalkingSimState;
|
||||
use crate::{CarID, Distance, PedestrianID, Tick};
|
||||
use crate::{CarID, PedestrianID, Tick};
|
||||
use abstutil::{deserialize_btreemap, serialize_btreemap};
|
||||
use dimensioned::si;
|
||||
use geom::{Distance, Duration};
|
||||
use map_model::{BusRoute, BusRouteID, BusStop, LaneID, Map, Path, PathRequest, Pathfinder};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
@ -143,7 +143,7 @@ impl TransitSimState {
|
||||
if stop.driving_pos.dist_along() == view.dist_along {
|
||||
// TODO constant for stop time
|
||||
self.buses.get_mut(&car).unwrap().state =
|
||||
BusState::AtStop(stop_idx, time + 10.0 * si::S);
|
||||
BusState::AtStop(stop_idx, time + Duration::seconds(10.0));
|
||||
events.push(Event::BusArrivedAtStop(car, stop.id));
|
||||
capture_backtrace("BusArrivedAtStop");
|
||||
if view.debug {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::driving::SimQueue;
|
||||
use crate::kinematics::Vehicle;
|
||||
use crate::{AgentID, CarID, Distance, Speed};
|
||||
use crate::{AgentID, CarID};
|
||||
use geom::{Distance, Speed};
|
||||
use map_model::Traversable;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
|
@ -4,14 +4,12 @@ use crate::parking::ParkingSimState;
|
||||
use crate::trips::TripManager;
|
||||
use crate::view::{AgentView, WorldView};
|
||||
use crate::{
|
||||
AgentID, Distance, DrawPedestrianInput, Event, ParkingSpot, PedestrianID, Speed, Tick, Time,
|
||||
TripID, TIMESTEP,
|
||||
AgentID, DrawPedestrianInput, Event, ParkingSpot, PedestrianID, Tick, TripID, TIMESTEP,
|
||||
};
|
||||
use abstutil;
|
||||
use abstutil::{deserialize_multimap, serialize_multimap, Error};
|
||||
use derivative::Derivative;
|
||||
use dimensioned::si;
|
||||
use geom::{Line, Pt2D};
|
||||
use geom::{Distance, Duration, Line, Pt2D, Speed};
|
||||
use map_model::{
|
||||
BuildingID, BusStopID, IntersectionID, LaneID, LaneType, Map, Path, PathStep, Position, Trace,
|
||||
Traversable, TurnID,
|
||||
@ -24,15 +22,9 @@ use std::collections::{BTreeMap, HashSet};
|
||||
// TODO tune these!
|
||||
// TODO make it vary, after we can easily serialize these
|
||||
// TODO temporarily very high to debug peds faster
|
||||
const SPEED: Speed = si::MeterPerSecond {
|
||||
value_unsafe: 3.9,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const SPEED: Speed = Speed::const_meters_per_second(3.9);
|
||||
|
||||
const TIME_TO_PREPARE_BIKE: Time = si::Second {
|
||||
value_unsafe: 15.0,
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
const TIME_TO_PREPARE_BIKE: Duration = Duration::const_seconds(15.0);
|
||||
|
||||
// A pedestrian can start from a parking spot (after driving and parking) or at a building.
|
||||
// A pedestrian can end at a parking spot (to start driving) or at a building.
|
||||
@ -86,7 +78,7 @@ impl SidewalkSpot {
|
||||
None
|
||||
} else {
|
||||
Some(SidewalkSpot {
|
||||
sidewalk_pos: Position::new(lanes[0], 0.0 * si::M),
|
||||
sidewalk_pos: Position::new(lanes[0], Distance::ZERO),
|
||||
connection: SidewalkPOI::Border(i),
|
||||
})
|
||||
}
|
||||
@ -186,7 +178,7 @@ impl Pedestrian {
|
||||
} else {
|
||||
goal_dist - self.dist_along
|
||||
};
|
||||
if dist_away <= 2.0 * SPEED * TIMESTEP {
|
||||
if dist_away <= SPEED * TIMESTEP * 2.0 {
|
||||
return match self.goal.connection {
|
||||
SidewalkPOI::ParkingSpot(spot) => Action::StartParkedCar(spot),
|
||||
SidewalkPOI::Building(id) => Action::StartCrossingPath(id),
|
||||
@ -201,7 +193,7 @@ impl Pedestrian {
|
||||
{
|
||||
let contraflow = self.path.current_step().is_contraflow();
|
||||
if (!contraflow && self.dist_along < self.on.length(map))
|
||||
|| (contraflow && self.dist_along > 0.0 * si::M)
|
||||
|| (contraflow && self.dist_along > Distance::ZERO)
|
||||
{
|
||||
return Action::Continue;
|
||||
}
|
||||
@ -217,7 +209,12 @@ impl Pedestrian {
|
||||
}
|
||||
|
||||
// If true, then we're completely done!
|
||||
fn step_cross_path(&mut self, events: &mut Vec<Event>, delta_time: Time, map: &Map) -> bool {
|
||||
fn step_cross_path(
|
||||
&mut self,
|
||||
events: &mut Vec<Event>,
|
||||
delta_time: Duration,
|
||||
map: &Map,
|
||||
) -> bool {
|
||||
let new_dist = delta_time * SPEED;
|
||||
|
||||
// TODO arguably a different direction would make this easier
|
||||
@ -227,7 +224,7 @@ impl Pedestrian {
|
||||
fp.dist_along >= map.get_b(fp.bldg).front_path.line.length()
|
||||
} else {
|
||||
fp.dist_along -= new_dist;
|
||||
if fp.dist_along < 0.0 * si::M {
|
||||
if fp.dist_along < Distance::ZERO {
|
||||
events.push(Event::PedReachedBuilding(self.id, fp.bldg));
|
||||
capture_backtrace("PedReachedBuilding");
|
||||
return true;
|
||||
@ -243,13 +240,13 @@ impl Pedestrian {
|
||||
false
|
||||
}
|
||||
|
||||
fn step_continue(&mut self, delta_time: Time, map: &Map) {
|
||||
fn step_continue(&mut self, delta_time: Duration, map: &Map) {
|
||||
let new_dist = delta_time * SPEED;
|
||||
|
||||
if self.path.current_step().is_contraflow() {
|
||||
self.dist_along -= new_dist;
|
||||
if self.dist_along < 0.0 * si::M {
|
||||
self.dist_along = 0.0 * si::M;
|
||||
if self.dist_along < Distance::ZERO {
|
||||
self.dist_along = Distance::ZERO;
|
||||
}
|
||||
} else {
|
||||
self.dist_along += new_dist;
|
||||
@ -280,7 +277,7 @@ impl Pedestrian {
|
||||
match self.path.current_step() {
|
||||
PathStep::Lane(id) => {
|
||||
self.on = Traversable::Lane(id);
|
||||
self.dist_along = 0.0 * si::M;
|
||||
self.dist_along = Distance::ZERO;
|
||||
}
|
||||
PathStep::ContraflowLane(id) => {
|
||||
self.on = Traversable::Lane(id);
|
||||
@ -288,7 +285,7 @@ impl Pedestrian {
|
||||
}
|
||||
PathStep::Turn(t) => {
|
||||
self.on = Traversable::Turn(t);
|
||||
self.dist_along = 0.0 * si::M;
|
||||
self.dist_along = Distance::ZERO;
|
||||
intersections.on_enter(Request::for_ped(self.id, t))?;
|
||||
}
|
||||
}
|
||||
@ -315,8 +312,7 @@ impl Pedestrian {
|
||||
);
|
||||
let line = Line::new(sidewalk_pos.pt(map), street_pos.pt(map));
|
||||
|
||||
let progress: f64 =
|
||||
((now - bp.started_at).as_time() / TIME_TO_PREPARE_BIKE).value_unsafe;
|
||||
let progress: f64 = (now - bp.started_at).as_time() / TIME_TO_PREPARE_BIKE;
|
||||
assert!(progress >= 0.0 && progress <= 1.0);
|
||||
let ratio = if bp.is_parking {
|
||||
1.0 - progress
|
||||
@ -324,7 +320,7 @@ impl Pedestrian {
|
||||
progress
|
||||
};
|
||||
|
||||
line.dist_along(ratio * line.length())
|
||||
line.dist_along(line.length() * ratio)
|
||||
} else {
|
||||
self.on.dist_along(self.dist_along, map).0
|
||||
}
|
||||
@ -393,7 +389,7 @@ impl WalkingSimState {
|
||||
pub fn step(
|
||||
&mut self,
|
||||
events: &mut Vec<Event>,
|
||||
delta_time: Time,
|
||||
delta_time: Duration,
|
||||
now: Tick,
|
||||
map: &Map,
|
||||
intersections: &mut IntersectionSimState,
|
||||
@ -581,7 +577,7 @@ impl WalkingSimState {
|
||||
let front_path = match params.start.connection {
|
||||
SidewalkPOI::Building(id) => Some(CrossingFrontPath {
|
||||
bldg: id,
|
||||
dist_along: 0.0 * si::M,
|
||||
dist_along: Distance::ZERO,
|
||||
going_to_sidewalk: true,
|
||||
}),
|
||||
_ => None,
|
||||
@ -627,7 +623,7 @@ impl WalkingSimState {
|
||||
debug: false,
|
||||
on: p.on,
|
||||
dist_along: p.dist_along,
|
||||
speed: if p.moving { SPEED } else { 0.0 * si::MPS },
|
||||
speed: if p.moving { SPEED } else { Speed::ZERO },
|
||||
vehicle: None,
|
||||
},
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user