the great control layer merge

This commit is contained in:
Dustin Carlino 2018-11-30 12:36:27 -08:00
parent 609c731fa0
commit 4d7c1203a6
41 changed files with 268 additions and 461 deletions

View File

@ -3,7 +3,6 @@
members = [
"abstutil",
"analyze_code",
"control",
"convert_osm",
"editor",
"ezgui",

View File

@ -1,12 +0,0 @@
[package]
name = "control"
version = "0.1.0"
authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
abstutil = { path = "../abstutil" }
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
log = "0.4.5"
map_model = { path = "../map_model" }
serde = "1.0"
serde_derive = "1.0"

View File

@ -1,95 +0,0 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
extern crate abstutil;
extern crate dimensioned;
#[macro_use]
extern crate log;
extern crate map_model;
#[macro_use]
extern crate serde_derive;
#[macro_use]
mod macros;
mod stop_signs;
mod traffic_signals;
use map_model::{IntersectionID, IntersectionType, Map};
use std::collections::{BTreeMap, HashMap};
pub use stop_signs::ControlStopSign;
pub use traffic_signals::ControlTrafficSignal;
// TODO awful name
pub struct ControlMap {
pub traffic_signals: HashMap<IntersectionID, ControlTrafficSignal>,
pub stop_signs: HashMap<IntersectionID, ControlStopSign>,
// Note that border nodes belong in neither!
}
impl ControlMap {
pub fn new(
map: &Map,
stop_signs: BTreeMap<IntersectionID, ControlStopSign>,
traffic_signals: BTreeMap<IntersectionID, ControlTrafficSignal>,
) -> ControlMap {
let mut ctrl = ControlMap {
traffic_signals: HashMap::new(),
stop_signs: HashMap::new(),
};
for i in map.all_intersections() {
match i.intersection_type {
IntersectionType::StopSign => {
ctrl.stop_signs
.insert(i.id, ControlStopSign::new(map, i.id));
}
IntersectionType::TrafficSignal => {
ctrl.traffic_signals
.insert(i.id, ControlTrafficSignal::new(map, i.id));
}
IntersectionType::Border => {}
};
}
for (i, s) in stop_signs.into_iter() {
ctrl.stop_signs.insert(i, s);
}
for (i, s) in traffic_signals.into_iter() {
ctrl.traffic_signals.insert(i, s);
}
ctrl
}
pub fn get_changed_stop_signs(&self) -> BTreeMap<IntersectionID, ControlStopSign> {
let mut h: BTreeMap<IntersectionID, ControlStopSign> = BTreeMap::new();
for (i, s) in &self.stop_signs {
if s.is_changed() {
h.insert(*i, s.clone());
}
}
h
}
pub fn get_changed_traffic_signals(&self) -> BTreeMap<IntersectionID, ControlTrafficSignal> {
let mut h = BTreeMap::new();
for (i, s) in &self.traffic_signals {
if s.is_changed() {
h.insert(*i, s.clone());
}
}
h
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, PartialOrd)]
pub enum TurnPriority {
// For stop signs: cars have to stop before doing this turn, and are accepted with the lowest priority.
// For traffic signals: can't do this turn at all.
Stop,
// Cars can do this immediately if there are no previously accepted conflicting turns.
Yield,
// These must be non-conflicting, and cars don't have to stop before doing this turn (unless a
// conflicting Yield has been accepted).
Priority,
}

View File

@ -1,37 +0,0 @@
// Call the log crate, but pre-set the target.
/*macro_rules! debug {
( $( $x:expr ),* ) => {
{
extern crate log;
log!(target: "control", log::Level::Debug, $( $x, )* );
}
}
}
macro_rules! info {
( $( $x:expr ),* ) => {
{
extern crate log;
log!(target: "control", log::Level::Info, $( $x, )* );
}
}
}*/
macro_rules! warn {
( $( $x:expr ),* ) => {
{
extern crate log;
log!(target: "control", log::Level::Warn, $( $x, )* );
}
}
}
/*macro_rules! error {
( $( $x:expr ),* ) => {
{
extern crate log;
log!(target: "control", log::Level::Error, $( $x, )* );
}
}
}*/

View File

@ -6,7 +6,6 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
aabb-quadtree = "0.1.0"
abstutil = { path = "../abstutil" }
control = { path = "../control" }
counter = "0.4.3"
cpuprofiler = "0.0.3"
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }

View File

@ -2,7 +2,6 @@
extern crate aabb_quadtree;
extern crate abstutil;
extern crate control;
extern crate counter;
extern crate cpuprofiler;
extern crate dimensioned;

View File

@ -1,5 +1,4 @@
use colors::ColorScheme;
use control::ControlMap;
use ezgui::Canvas;
use geom::Pt2D;
use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParcelID, TurnID};
@ -30,14 +29,14 @@ impl ID {
}
}
pub fn debug(&self, map: &Map, control_map: &ControlMap, sim: &mut Sim, draw_map: &DrawMap) {
pub fn debug(&self, map: &Map, sim: &mut Sim, draw_map: &DrawMap) {
match *self {
ID::Lane(id) => {
map.get_l(id).dump_debug();
}
ID::Intersection(id) => {
map.get_i(id).dump_debug();
sim.debug_intersection(id, control_map);
sim.debug_intersection(id, map);
}
ID::Turn(id) => {
map.get_t(id).dump_debug(map);
@ -102,7 +101,6 @@ impl ID {
pub struct Ctx<'a> {
pub cs: &'a mut ColorScheme,
pub map: &'a Map,
pub control_map: &'a ControlMap,
pub draw_map: &'a DrawMap,
pub canvas: &'a Canvas,
pub sim: &'a Sim,

View File

@ -44,7 +44,6 @@ impl Plugin for DebugObjectsState {
} else if ctx.input.key_pressed(Key::D, "debug") {
id.debug(
&ctx.primary.map,
&ctx.primary.control_map,
&mut ctx.primary.sim,
&ctx.primary.draw_map,
);

View File

@ -1,10 +1,9 @@
use control::ControlMap;
use ezgui::{GfxCtx, Wizard, WrappedWizard};
use map_model::Map;
use objects::{Ctx, SIM_SETUP};
use piston::input::Key;
use plugins::{choose_edits, Plugin, PluginCtx};
use sim::{MapEdits, SimFlags};
use sim::SimFlags;
use ui::{PerMapUI, PluginsPerMap};
pub enum EditsManager {
@ -36,7 +35,6 @@ impl Plugin for EditsManager {
if manage_edits(
&mut ctx.primary.current_flags,
&ctx.primary.map,
&ctx.primary.control_map,
ctx.kml,
&mut new_primary,
wizard.wrap(ctx.input),
@ -76,7 +74,6 @@ impl Plugin for EditsManager {
fn manage_edits(
current_flags: &mut SimFlags,
map: &Map,
control_map: &ControlMap,
kml: &Option<String>,
new_primary: &mut Option<(PerMapUI, PluginsPerMap)>,
mut wizard: WrappedWizard,
@ -93,14 +90,8 @@ fn manage_edits(
// Slow to create this every tick just to get the description? It's actually frozen once the
// wizard is started...
let mut edits = MapEdits {
edits_name: current_flags.edits_name.to_string(),
map_name: map.get_name().to_string(),
road_edits: map.get_road_edits().clone(),
stop_signs: control_map.get_changed_stop_signs(),
traffic_signals: control_map.get_changed_traffic_signals(),
};
edits.road_edits.edits_name = edits.edits_name.clone();
let mut edits = map.get_edits().clone();
edits.edits_name = edits.edits_name.clone();
match wizard
.choose_string(&format!("Manage {}", edits.describe()), choices)?

View File

@ -15,17 +15,16 @@ impl RoadEditor {
impl Plugin for RoadEditor {
fn event(&mut self, ctx: PluginCtx) -> bool {
let (input, selected, map, draw_map, control_map, sim) = (
let (input, selected, map, draw_map, sim) = (
ctx.input,
ctx.primary.current_selection,
&mut ctx.primary.map,
&mut ctx.primary.draw_map,
&ctx.primary.control_map,
&mut ctx.primary.sim,
);
let mut edits = map.get_road_edits().clone();
let mut edits = map.get_edits().clone();
// TODO a bit awkward that we can't pull this info from RoadEdits easily
// TODO a bit awkward that we can't pull this info from edits easily
let mut changed: Option<(LaneID, LaneType)> = None;
if !self.active && selected.is_none() {
@ -93,10 +92,10 @@ impl Plugin for RoadEditor {
}
}
// TODO Pretty sure control map needs to recalculate based on the new turns
// TODO Pretty sure control layer needs to recalculate based on the new turns
let old_type = map.get_l(id).lane_type;
map.edit_lane_type(id, new_type);
draw_map.edit_lane_type(id, map, control_map);
draw_map.edit_lane_type(id, map);
sim.edit_lane_type(id, old_type, map);
// Add turns back

View File

@ -81,10 +81,10 @@ impl Plugin for SimController {
self.last_step = Some(Instant::now());
self.benchmark = Some(primary.sim.start_benchmark());
} else if input.unimportant_key_pressed(Key::M, SIM, "run one step") {
primary.sim.step(&primary.map, &primary.control_map);
primary.sim.step(&primary.map);
primary.recalculate_current_selection = true;
if let Some((s, _)) = secondary {
s.sim.step(&s.map, &s.control_map);
s.sim.step(&s.map);
}
}
}
@ -118,10 +118,10 @@ impl Plugin for SimController {
// TODO https://gafferongames.com/post/fix_your_timestep/
let dt_s = elapsed_seconds(tick);
if dt_s >= TIMESTEP.value_unsafe / self.desired_speed {
primary.sim.step(&primary.map, &primary.control_map);
primary.sim.step(&primary.map);
primary.recalculate_current_selection = true;
if let Some((s, _)) = secondary {
s.sim.step(&s.map, &s.control_map);
s.sim.step(&s.map);
}
self.last_step = Some(Instant::now());
}

View File

@ -1,8 +1,7 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use control::TurnPriority;
use ezgui::Color;
use map_model::IntersectionID;
use map_model::{IntersectionID, TurnPriority};
use objects::{Ctx, ID};
use piston::input::Key;
use plugins::{Plugin, PluginCtx};
@ -29,14 +28,13 @@ impl StopSignEditor {
impl Plugin for StopSignEditor {
fn event(&mut self, ctx: PluginCtx) -> bool {
let input = ctx.input;
let map = &ctx.primary.map;
let control_map = &mut ctx.primary.control_map;
let map = &mut ctx.primary.map;
let selected = ctx.primary.current_selection;
if *self == StopSignEditor::Inactive {
match selected {
Some(ID::Intersection(id)) => {
if control_map.stop_signs.contains_key(&id)
if map.maybe_get_stop_sign(id).is_some()
&& input.key_pressed(Key::E, &format!("edit stop signs for {}", id))
{
*self = StopSignEditor::Active(id);
@ -55,7 +53,8 @@ impl Plugin for StopSignEditor {
new_state = Some(StopSignEditor::Inactive);
} else if let Some(ID::Turn(id)) = selected {
if id.parent == *i {
let sign = &mut control_map.stop_signs.get_mut(i).unwrap();
let mut sign = map.get_stop_sign(*i).clone();
match sign.get_priority(id) {
TurnPriority::Priority => {
if input.key_pressed(Key::D2, "make this turn yield") {
@ -86,6 +85,8 @@ impl Plugin for StopSignEditor {
}
}
};
map.edit_stop_sign(sign);
}
}
}
@ -106,7 +107,7 @@ impl Plugin for StopSignEditor {
if t.parent != *i {
return Some(ctx.cs.get("irrelevant turn", Color::grey(0.3)));
}
match ctx.control_map.stop_signs[i].get_priority(t) {
match ctx.map.get_stop_sign(*i).get_priority(t) {
TurnPriority::Priority => {
Some(ctx.cs.get("priority stop sign turn", Color::GREEN))
}

View File

@ -2,9 +2,8 @@
// TODO how to edit cycle time?
use control::TurnPriority;
use ezgui::Color;
use map_model::IntersectionID;
use map_model::{IntersectionID, TurnPriority};
use objects::{Ctx, ID};
use piston::input::Key;
use plugins::{Plugin, PluginCtx};
@ -37,14 +36,13 @@ impl TrafficSignalEditor {
impl Plugin for TrafficSignalEditor {
fn event(&mut self, ctx: PluginCtx) -> bool {
let input = ctx.input;
let map = &ctx.primary.map;
let control_map = &mut ctx.primary.control_map;
let map = &mut ctx.primary.map;
let selected = ctx.primary.current_selection;
if *self == TrafficSignalEditor::Inactive {
match selected {
Some(ID::Intersection(id)) => {
if control_map.traffic_signals.contains_key(&id)
if map.maybe_get_traffic_signal(id).is_some()
&& input.key_pressed(Key::E, &format!("edit traffic signal for {}", id))
{
*self = TrafficSignalEditor::Active {
@ -67,7 +65,7 @@ impl Plugin for TrafficSignalEditor {
} else {
// Change cycles
{
let cycles = &control_map.traffic_signals[&i].cycles;
let cycles = &map.get_traffic_signal(*i).cycles;
if let Some(n) = input.number_chosen(
cycles.len(),
&format!(
@ -84,28 +82,33 @@ impl Plugin for TrafficSignalEditor {
// Change turns
if let Some(ID::Turn(id)) = selected {
if id.parent == *i {
let cycle =
&mut control_map.traffic_signals.get_mut(&i).unwrap().cycles
[*current_cycle];
if cycle.get_priority(id) == TurnPriority::Priority {
if input
.key_pressed(Key::Backspace, "remove this turn from this cycle")
{
cycle.remove(id);
}
} else if cycle.could_be_priority_turn(id, map) {
if input.key_pressed(
Key::Space,
"add this turn to this cycle as priority",
) {
cycle.add(id, TurnPriority::Priority);
}
} else if cycle.get_priority(id) == TurnPriority::Stop {
if input.key_pressed(Key::Y, "add this turn to this cycle as yield")
{
cycle.add(id, TurnPriority::Yield);
let mut signal = map.get_traffic_signal(*i).clone();
{
let cycle = &mut signal.cycles[*current_cycle];
if cycle.get_priority(id) == TurnPriority::Priority {
if input.key_pressed(
Key::Backspace,
"remove this turn from this cycle",
) {
cycle.remove(id);
}
} else if cycle.could_be_priority_turn(id, map) {
if input.key_pressed(
Key::Space,
"add this turn to this cycle as priority",
) {
cycle.add(id, TurnPriority::Priority);
}
} else if cycle.get_priority(id) == TurnPriority::Stop {
if input
.key_pressed(Key::Y, "add this turn to this cycle as yield")
{
cycle.add(id, TurnPriority::Yield);
}
}
}
map.edit_traffic_signal(signal);
}
}
}
@ -128,7 +131,7 @@ impl Plugin for TrafficSignalEditor {
return Some(ctx.cs.get("irrelevant turn", Color::grey(0.3)));
}
let cycle = &ctx.control_map.traffic_signals[&i].cycles[*current_cycle];
let cycle = &ctx.map.get_traffic_signal(*i).cycles[*current_cycle];
// TODO maybe something to indicate unused in any cycle so far
let could_be_priority = cycle.could_be_priority_turn(t, ctx.map);

View File

@ -1,8 +1,9 @@
use control::{ControlTrafficSignal, TurnPriority};
use dimensioned::si;
use ezgui::{Color, GfxCtx};
use geom::Circle;
use map_model::{IntersectionID, LaneID, TurnType, LANE_THICKNESS};
use map_model::{
ControlTrafficSignal, IntersectionID, LaneID, TurnPriority, TurnType, LANE_THICKNESS,
};
use objects::{Ctx, ID};
use piston::input::Key;
use plugins::{Plugin, PluginCtx};
@ -92,7 +93,7 @@ impl Plugin for TurnCyclerState {
//draw_map.get_l(id).draw_debug(g, cs, map.get_l(id));
}
TurnCyclerState::Intersection(id) => {
if let Some(signal) = ctx.control_map.traffic_signals.get(&id) {
if let Some(signal) = ctx.map.maybe_get_traffic_signal(*id) {
draw_traffic_signal(signal, g, ctx);
}
}

View File

@ -84,9 +84,9 @@ impl Renderable for DrawIntersection {
return ctx.cs.get("border intersection", Color::rgb(50, 205, 50));
}
let changed = if let Some(s) = ctx.control_map.traffic_signals.get(&self.id) {
let changed = if let Some(s) = ctx.map.maybe_get_traffic_signal(self.id) {
s.is_changed()
} else if let Some(s) = ctx.control_map.stop_signs.get(&self.id) {
} else if let Some(s) = ctx.map.maybe_get_stop_sign(self.id) {
s.is_changed()
} else {
false

View File

@ -1,7 +1,6 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use colors::ColorScheme;
use control::ControlMap;
use dimensioned::si;
use ezgui::{Color, GfxCtx, Text};
use geom::{Bounds, Circle, Line, Polygon, Pt2D};
@ -52,7 +51,7 @@ pub struct DrawLane {
}
impl DrawLane {
pub fn new(lane: &Lane, map: &Map, control_map: &ControlMap) -> DrawLane {
pub fn new(lane: &Lane, map: &Map) -> DrawLane {
let road = map.get_r(lane.parent);
let polygon = lane.lane_center_pts.make_polygons_blindly(LANE_THICKNESS);
@ -86,7 +85,7 @@ impl DrawLane {
if lane.is_driving()
&& map.get_i(lane.dst_i).intersection_type == IntersectionType::StopSign
{
if let Some(m) = calculate_stop_sign_line(lane, control_map) {
if let Some(m) = calculate_stop_sign_line(lane, map) {
markings.push(m);
}
}
@ -269,8 +268,8 @@ fn calculate_driving_lines(lane: &Lane, parent: &Road) -> Option<Marking> {
})
}
fn calculate_stop_sign_line(lane: &Lane, control_map: &ControlMap) -> Option<Marking> {
if control_map.stop_signs[&lane.dst_i].is_priority_lane(lane.id) {
fn calculate_stop_sign_line(lane: &Lane, map: &Map) -> Option<Marking> {
if map.get_stop_sign(lane.dst_i).is_priority_lane(lane.id) {
return None;
}

View File

@ -2,7 +2,6 @@
use aabb_quadtree::QuadTree;
use abstutil::Timer;
use control::ControlMap;
use geom::Bounds;
use kml::ExtraShape;
use map_model::{
@ -40,17 +39,12 @@ pub struct DrawMap {
}
impl DrawMap {
pub fn new(
map: &Map,
control_map: &ControlMap,
raw_extra_shapes: Vec<ExtraShape>,
timer: &mut Timer,
) -> DrawMap {
pub fn new(map: &Map, raw_extra_shapes: Vec<ExtraShape>, timer: &mut Timer) -> DrawMap {
let mut lanes: Vec<DrawLane> = Vec::new();
timer.start_iter("make DrawLanes", map.all_lanes().len());
for l in map.all_lanes() {
timer.next();
lanes.push(DrawLane::new(l, map, control_map));
lanes.push(DrawLane::new(l, map));
}
let mut turn_to_lane_offset: HashMap<TurnID, usize> = HashMap::new();
@ -172,9 +166,9 @@ impl DrawMap {
}
}
pub fn edit_lane_type(&mut self, id: LaneID, map: &Map, control_map: &ControlMap) {
pub fn edit_lane_type(&mut self, id: LaneID, map: &Map) {
// No need to edit the quadtree; the bbox shouldn't depend on lane type.
self.lanes[id.0] = DrawLane::new(map.get_l(id), map, control_map);
self.lanes[id.0] = DrawLane::new(map.get_l(id), map);
}
pub fn edit_remove_turn(&mut self, id: TurnID) {

View File

@ -4,7 +4,6 @@
use abstutil;
use colors::ColorScheme;
use control::ControlMap;
//use cpuprofiler;
use ezgui::{Canvas, Color, GfxCtx, Text, UserInput, BOTTOM_LEFT, GUI};
use kml;
@ -97,7 +96,6 @@ impl GUI for UI {
Ctx {
cs: &mut self.cs.borrow_mut(),
map: &self.primary.map,
control_map: &self.primary.control_map,
draw_map: &self.primary.draw_map,
canvas: &self.canvas,
sim: &self.primary.sim,
@ -116,7 +114,6 @@ impl GUI for UI {
Ctx {
cs: &mut self.cs.borrow_mut(),
map: &self.primary.map,
control_map: &self.primary.control_map,
draw_map: &self.primary.draw_map,
canvas: &self.canvas,
sim: &self.primary.sim,
@ -130,7 +127,6 @@ impl GUI for UI {
Ctx {
cs: &mut self.cs.borrow_mut(),
map: &self.primary.map,
control_map: &self.primary.control_map,
draw_map: &self.primary.draw_map,
canvas: &self.canvas,
sim: &self.primary.sim,
@ -144,7 +140,6 @@ impl GUI for UI {
Ctx {
cs: &mut self.cs.borrow_mut(),
map: &self.primary.map,
control_map: &self.primary.control_map,
draw_map: &self.primary.draw_map,
canvas: &self.canvas,
sim: &self.primary.sim,
@ -161,7 +156,6 @@ impl GUI for UI {
pub struct PerMapUI {
pub map: Map,
pub draw_map: DrawMap,
pub control_map: ControlMap,
pub sim: Sim,
pub current_selection: Option<ID>,
@ -204,8 +198,7 @@ impl PerMapUI {
pub fn new(flags: SimFlags, kml: &Option<String>) -> (PerMapUI, PluginsPerMap) {
let mut timer = abstutil::Timer::new("setup PerMapUI");
let (map, control_map, sim) =
sim::load(flags.clone(), Some(Tick::from_seconds(30)), &mut timer);
let (map, sim) = sim::load(flags.clone(), Some(Tick::from_seconds(30)), &mut timer);
let extra_shapes: Vec<kml::ExtraShape> = if let Some(path) = kml {
if path.ends_with(".kml") {
kml::load(&path, &map.get_gps_bounds(), &mut timer)
@ -221,7 +214,7 @@ impl PerMapUI {
};
timer.start("draw_map");
let draw_map = DrawMap::new(&map, &control_map, extra_shapes, &mut timer);
let draw_map = DrawMap::new(&map, extra_shapes, &mut timer);
timer.stop("draw_map");
let steepness_viz = plugins::steep::SteepnessVisualizer::new(&map);
@ -233,7 +226,6 @@ impl PerMapUI {
let state = PerMapUI {
map,
draw_map,
control_map,
sim,
current_selection: None,
@ -427,7 +419,6 @@ impl UI {
let ctx = Ctx {
cs: &mut self.cs.borrow_mut(),
map: &self.primary.map,
control_map: &self.primary.control_map,
draw_map: &self.primary.draw_map,
canvas: &self.canvas,
sim: &self.primary.sim,

View File

@ -5,7 +5,6 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
abstutil = { path = "../abstutil" }
control = { path = "../control" }
cpuprofiler = "0.0.3"
log = "0.4.5"
map_model = { path = "../map_model" }

View File

@ -1,7 +1,6 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
extern crate abstutil;
extern crate control;
extern crate cpuprofiler;
extern crate log;
extern crate map_model;
@ -35,7 +34,7 @@ fn main() {
// TODO not the ideal way to distinguish what thing we loaded
let load = flags.sim_flags.load.clone();
let mut timer = Timer::new("setup headless");
let (map, control_map, mut sim) = sim::load(
let (map, mut sim) = sim::load(
flags.sim_flags,
Some(sim::Tick::from_seconds(30)),
&mut timer,
@ -63,7 +62,6 @@ fn main() {
.unwrap();
sim.run_until_done(
&map,
&control_map,
Box::new(move |sim| {
if Some(sim.time) == save_at {
sim.save();

View File

@ -1,29 +1,44 @@
use abstutil::{deserialize_btreemap, serialize_btreemap};
use abstutil;
use std::collections::BTreeMap;
use {Lane, LaneType, Road, RoadID};
use {ControlStopSign, ControlTrafficSignal, IntersectionID, Lane, LaneType, Road, RoadID};
// TODO bring in the intersection modifications from the control crate here. for now, road edits
// are here, since map construction maybe needs to know these?
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RoadEdits {
pub struct MapEdits {
pub edits_name: String,
pub map_name: String,
// TODO detect when we wind up editing back to the original thing
#[serde(
serialize_with = "serialize_btreemap",
deserialize_with = "deserialize_btreemap"
)]
pub(crate) roads: BTreeMap<RoadID, RoadEdit>,
pub(crate) stop_signs: BTreeMap<IntersectionID, ControlStopSign>,
pub(crate) traffic_signals: BTreeMap<IntersectionID, ControlTrafficSignal>,
}
impl RoadEdits {
pub fn new() -> RoadEdits {
RoadEdits {
impl MapEdits {
pub fn new(map_name: &str) -> MapEdits {
MapEdits {
// Something has to fill this out later
edits_name: "no_edits".to_string(),
map_name: map_name.to_string(),
roads: BTreeMap::new(),
stop_signs: BTreeMap::new(),
traffic_signals: BTreeMap::new(),
}
}
pub fn describe(&self) -> String {
format!(
"map edits \"{}\" ({} roads, {} stop signs, {} traffic signals",
self.edits_name,
self.roads.len(),
self.stop_signs.len(),
self.traffic_signals.len()
)
}
pub fn save(&self) {
abstutil::save_object("edits", &self.map_name, &self.edits_name, self);
}
pub fn change_lane_type(
&mut self,
reason: EditReason,
@ -45,10 +60,6 @@ impl RoadEdits {
}
false
}
pub fn len(&self) -> usize {
self.roads.len()
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]

View File

@ -30,6 +30,8 @@ mod parcel;
mod pathfind;
pub mod raw_data;
mod road;
mod stop_signs;
mod traffic_signals;
mod traversable;
mod turn;
@ -37,7 +39,7 @@ use abstutil::Cloneable;
pub use area::{Area, AreaID, AreaType};
pub use building::{Building, BuildingID, FrontPath};
pub use bus_stop::{BusRoute, BusRouteID, BusStop, BusStopID};
pub use edits::{EditReason, RoadEdits};
pub use edits::{EditReason, MapEdits};
pub use find_closest::FindClosest;
pub use intersection::{Intersection, IntersectionID, IntersectionType};
pub use lane::{Lane, LaneID, LaneType, PARKING_SPOT_LENGTH};
@ -46,9 +48,12 @@ pub use map::Map;
pub use parcel::{Parcel, ParcelID};
pub use pathfind::{Path, PathRequest, PathStep, Pathfinder, Trace};
pub use road::{Road, RoadID};
pub use stop_signs::ControlStopSign;
pub use traffic_signals::ControlTrafficSignal;
pub use traversable::{Position, Traversable};
pub use turn::{Turn, TurnID, TurnType};
pub use turn::{Turn, TurnID, TurnPriority, TurnType};
pub const LANE_THICKNESS: f64 = 2.5;
impl Cloneable for IntersectionID {}
impl Cloneable for MapEdits {}

View File

@ -1,8 +1,5 @@
use edits::RoadEdits;
use lane::LaneType;
use raw_data;
use road::RoadID;
use std::iter;
use {raw_data, LaneType, MapEdits, RoadID};
// (original direction, reversed direction)
fn get_lanes(r: &raw_data::Road) -> (Vec<LaneType>, Vec<LaneType>) {
@ -118,7 +115,7 @@ impl LaneSpec {
}
}
pub fn get_lane_specs(r: &raw_data::Road, id: RoadID, edits: &RoadEdits) -> Vec<LaneSpec> {
pub fn get_lane_specs(r: &raw_data::Road, id: RoadID, edits: &MapEdits) -> Vec<LaneSpec> {
let (side1_types, side2_types) = if let Some(e) = edits.roads.get(&id) {
info!("Using edits for {}", id);
(e.forwards_lanes.clone(), e.backwards_lanes.clone())

View File

@ -2,7 +2,7 @@
use abstutil;
use abstutil::{deserialize_btreemap, serialize_btreemap, Error, Timer};
use edits::RoadEdits;
use edits::MapEdits;
use geom::{Bounds, GPSBounds, HashablePt2D, PolyLine, Pt2D};
use make;
use raw_data;
@ -10,9 +10,9 @@ use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::io;
use std::path;
use {
Area, AreaID, Building, BuildingID, BusRoute, BusRouteID, BusStop, BusStopID, Intersection,
IntersectionID, IntersectionType, Lane, LaneID, LaneType, Parcel, ParcelID, Road, RoadID, Turn,
TurnID, LANE_THICKNESS,
Area, AreaID, Building, BuildingID, BusRoute, BusRouteID, BusStop, BusStopID, ControlStopSign,
ControlTrafficSignal, Intersection, IntersectionID, IntersectionType, Lane, LaneID, LaneType,
Parcel, ParcelID, Road, RoadID, Turn, TurnID, LANE_THICKNESS,
};
#[derive(Serialize, Deserialize, Debug)]
@ -35,15 +35,18 @@ pub struct Map {
bus_routes: Vec<BusRoute>,
areas: Vec<Area>,
stop_signs: BTreeMap<IntersectionID, ControlStopSign>,
traffic_signals: BTreeMap<IntersectionID, ControlTrafficSignal>,
// Note that border nodes belong in neither!
gps_bounds: GPSBounds,
bounds: Bounds,
name: String,
road_edits: RoadEdits,
edits: MapEdits,
}
impl Map {
pub fn new(path: &str, road_edits: RoadEdits, timer: &mut Timer) -> Result<Map, io::Error> {
pub fn new(path: &str, edits: MapEdits, timer: &mut Timer) -> Result<Map, io::Error> {
let data: raw_data::Map = abstutil::read_binary(path, timer)?;
Ok(Map::create_from_raw(
path::Path::new(path)
@ -53,7 +56,7 @@ impl Map {
.into_string()
.unwrap(),
data,
road_edits,
edits,
timer,
))
}
@ -61,7 +64,7 @@ impl Map {
pub fn create_from_raw(
name: String,
mut data: raw_data::Map,
road_edits: RoadEdits,
edits: MapEdits,
timer: &mut Timer,
) -> Map {
timer.start("raw_map to Map");
@ -75,7 +78,7 @@ impl Map {
let mut m = Map {
name,
road_edits,
edits,
gps_bounds: gps_bounds.clone(),
bounds: bounds.clone(),
roads: Vec::new(),
@ -87,6 +90,8 @@ impl Map {
bus_stops: BTreeMap::new(),
bus_routes: Vec::new(),
areas: Vec::new(),
stop_signs: BTreeMap::new(),
traffic_signals: BTreeMap::new(),
};
let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new();
@ -148,7 +153,7 @@ impl Map {
});
// TODO move this to make/lanes.rs too
for lane in make::get_lane_specs(r, road_id, &m.road_edits) {
for lane in make::get_lane_specs(r, road_id, &m.edits) {
let id = LaneID(counter);
counter += 1;
@ -243,6 +248,29 @@ impl Map {
m.intersections[t.id.parent.0].turns.push(t.id);
}
let mut stop_signs: BTreeMap<IntersectionID, ControlStopSign> = BTreeMap::new();
let mut traffic_signals: BTreeMap<IntersectionID, ControlTrafficSignal> = BTreeMap::new();
for i in &m.intersections {
match i.intersection_type {
IntersectionType::StopSign => {
stop_signs.insert(i.id, ControlStopSign::new(&m, i.id));
}
IntersectionType::TrafficSignal => {
traffic_signals.insert(i.id, ControlTrafficSignal::new(&m, i.id));
}
IntersectionType::Border => {}
};
}
// Override with edits
for (i, ss) in &m.edits.stop_signs {
stop_signs.insert(*i, ss.clone());
}
for (i, ts) in &m.edits.traffic_signals {
traffic_signals.insert(*i, ts.clone());
}
m.stop_signs = stop_signs;
m.traffic_signals = traffic_signals;
make::make_all_buildings(
&mut m.buildings,
&data.buildings,
@ -286,10 +314,11 @@ impl Map {
m
}
// The caller has to clone get_road_edits(), mutate, actualize the changes, then store them
// The caller has to clone get_edits(), mutate, actualize the changes, then store them
// here.
pub fn store_new_edits(&mut self, edits: RoadEdits) {
self.road_edits = edits;
// TODO Only road editor calls this. Stop sign / traffic signal editor have a nicer pattern.
pub fn store_new_edits(&mut self, edits: MapEdits) {
self.edits = edits;
}
pub fn edit_lane_type(&mut self, lane: LaneID, new_type: LaneType) {
@ -313,6 +342,16 @@ impl Map {
}
}
pub fn edit_stop_sign(&mut self, sign: ControlStopSign) {
self.edits.stop_signs.insert(sign.id, sign.clone());
self.stop_signs.insert(sign.id, sign);
}
pub fn edit_traffic_signal(&mut self, signal: ControlTrafficSignal) {
self.edits.traffic_signals.insert(signal.id, signal.clone());
self.traffic_signals.insert(signal.id, signal);
}
pub fn all_roads(&self) -> &Vec<Road> {
&self.roads
}
@ -373,6 +412,14 @@ impl Map {
self.bus_stops.get(&id)
}
pub fn maybe_get_stop_sign(&self, id: IntersectionID) -> Option<&ControlStopSign> {
self.stop_signs.get(&id)
}
pub fn maybe_get_traffic_signal(&self, id: IntersectionID) -> Option<&ControlTrafficSignal> {
self.traffic_signals.get(&id)
}
pub fn get_r(&self, id: RoadID) -> &Road {
&self.roads[id.0]
}
@ -401,6 +448,14 @@ impl Map {
&self.areas[id.0]
}
pub fn get_stop_sign(&self, id: IntersectionID) -> &ControlStopSign {
&self.stop_signs[&id]
}
pub fn get_traffic_signal(&self, id: IntersectionID) -> &ControlTrafficSignal {
&self.traffic_signals[&id]
}
// All these helpers should take IDs and return objects.
pub fn get_source_intersection(&self, l: LaneID) -> &Intersection {
@ -483,8 +538,8 @@ impl Map {
&self.name
}
pub fn get_road_edits(&self) -> &RoadEdits {
&self.road_edits
pub fn get_edits(&self) -> &MapEdits {
&self.edits
}
pub fn all_bus_stops(&self) -> &BTreeMap<BusStopID, BusStop> {
@ -543,10 +598,7 @@ impl Map {
}
pub fn save(&self) {
let path = format!(
"../data/maps/{}_{}.abst",
self.name, self.road_edits.edits_name
);
let path = format!("../data/maps/{}_{}.abst", self.name, self.edits.edits_name);
info!("Saving {}...", path);
abstutil::write_binary(&path, self).expect(&format!("Saving {} failed", path));
info!("Saved {}", path);

View File

@ -1,13 +1,10 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
use map_model::{IntersectionID, LaneID, Map, TurnID, TurnType};
use std::collections::{BTreeMap, HashMap, HashSet};
use TurnPriority;
use {IntersectionID, LaneID, Map, TurnID, TurnPriority, TurnType};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ControlStopSign {
intersection: IntersectionID,
pub id: IntersectionID,
#[serde(
serialize_with = "serialize_btreemap",
deserialize_with = "deserialize_btreemap"
@ -18,9 +15,9 @@ pub struct ControlStopSign {
}
impl ControlStopSign {
pub fn new(map: &Map, intersection: IntersectionID) -> ControlStopSign {
let ss = smart_assignment(map, intersection);
ss.validate(map, intersection).unwrap();
pub fn new(map: &Map, id: IntersectionID) -> ControlStopSign {
let ss = smart_assignment(map, id);
ss.validate(map).unwrap();
ss
}
@ -57,9 +54,9 @@ impl ControlStopSign {
.is_some()
}
fn validate(&self, map: &Map, intersection: IntersectionID) -> Result<(), Error> {
fn validate(&self, map: &Map) -> Result<(), Error> {
// Does the assignment cover the correct set of turns?
let all_turns = &map.get_i(intersection).turns;
let all_turns = &map.get_i(self.id).turns;
assert_eq!(self.turns.len(), all_turns.len());
for t in all_turns {
assert!(self.turns.contains_key(t));
@ -91,9 +88,9 @@ impl ControlStopSign {
}
}
fn smart_assignment(map: &Map, intersection: IntersectionID) -> ControlStopSign {
if map.get_i(intersection).roads.len() <= 2 {
return for_degenerate_and_deadend(map, intersection);
fn smart_assignment(map: &Map, id: IntersectionID) -> ControlStopSign {
if map.get_i(id).roads.len() <= 2 {
return for_degenerate_and_deadend(map, id);
}
// Higher numbers are higher rank roads
@ -102,10 +99,10 @@ fn smart_assignment(map: &Map, intersection: IntersectionID) -> ControlStopSign
let mut highest_rank = 0;
// TODO should just be incoming, but because of weirdness with sidewalks...
for l in map
.get_i(intersection)
.get_i(id)
.incoming_lanes
.iter()
.chain(map.get_i(intersection).outgoing_lanes.iter())
.chain(map.get_i(id).outgoing_lanes.iter())
{
let r = map.get_parent(*l);
let rank = if let Some(highway) = r.osm_tags.get("highway") {
@ -141,15 +138,15 @@ fn smart_assignment(map: &Map, intersection: IntersectionID) -> ControlStopSign
ranks.insert(rank);
}
if ranks.len() == 1 {
return all_way_stop(map, intersection);
return all_way_stop(map, id);
}
let mut ss = ControlStopSign {
intersection,
id,
turns: BTreeMap::new(),
changed: false,
};
for t in &map.get_i(intersection).turns {
for t in &map.get_i(id).turns {
if rank_per_incoming_lane[&t.src] == highest_rank {
// If it's the highest rank road, make the straight and right turns priority (if
// possible) and other turns yield.
@ -169,25 +166,25 @@ fn smart_assignment(map: &Map, intersection: IntersectionID) -> ControlStopSign
ss
}
fn all_way_stop(map: &Map, intersection: IntersectionID) -> ControlStopSign {
fn all_way_stop(map: &Map, id: IntersectionID) -> ControlStopSign {
let mut ss = ControlStopSign {
intersection,
id,
turns: BTreeMap::new(),
changed: false,
};
for t in &map.get_i(intersection).turns {
for t in &map.get_i(id).turns {
ss.turns.insert(*t, TurnPriority::Stop);
}
ss
}
fn for_degenerate_and_deadend(map: &Map, i: IntersectionID) -> ControlStopSign {
fn for_degenerate_and_deadend(map: &Map, id: IntersectionID) -> ControlStopSign {
let mut ss = ControlStopSign {
intersection: i,
id,
turns: BTreeMap::new(),
changed: false,
};
for t in &map.get_i(i).turns {
for t in &map.get_i(id).turns {
// Only the crosswalks should conflict with other turns.
let priority = match map.get_t(*t).turn_type {
TurnType::Crosswalk => TurnPriority::Stop,
@ -199,9 +196,9 @@ fn for_degenerate_and_deadend(map: &Map, i: IntersectionID) -> ControlStopSign {
// Due to a few observed issues (multiple driving lanes road (a temporary issue) and bad
// intersection geometry), sometimes more turns conflict than really should. For now, just
// detect and fallback to an all-way stop.
if let Err(err) = ss.validate(map, i) {
warn!("Giving up on for_degenerate_and_deadend({}): {}", i, err);
return all_way_stop(map, i);
if let Err(err) = ss.validate(map) {
warn!("Giving up on for_degenerate_and_deadend({}): {}", id, err);
return all_way_stop(map, id);
}
ss

View File

@ -1,8 +1,7 @@
use dimensioned::si;
use map_model::{IntersectionID, Map, TurnID};
use std;
use std::collections::BTreeSet;
use TurnPriority;
use {IntersectionID, Map, TurnID, TurnPriority};
const CYCLE_DURATION: si::Second<f64> = si::Second {
value_unsafe: 15.0,

View File

@ -31,6 +31,18 @@ pub enum TurnType {
Other,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, PartialOrd)]
pub enum TurnPriority {
// For stop signs: cars have to stop before doing this turn, and are accepted with the lowest priority.
// For traffic signals: can't do this turn at all.
Stop,
// Cars can do this immediately if there are no previously accepted conflicting turns.
Yield,
// These must be non-conflicting, and cars don't have to stop before doing this turn (unless a
// conflicting Yield has been accepted).
Priority,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Turn {
pub id: TurnID,

View File

@ -19,7 +19,7 @@ fn main() {
"precompute {} with {}",
flags.load, flags.edits_name
));
let (map, _, _) = sim::load(flags, None, &mut timer);
let (map, _) = sim::load(flags, None, &mut timer);
timer.start("save map");
map.save();
timer.stop("save map");

View File

@ -6,7 +6,6 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
abstutil = { path = "../abstutil" }
backtrace = "0.3.9"
control = { path = "../control" }
derivative = "1.0.0"
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
geom = { path = "../geom" }

View File

@ -1,5 +1,4 @@
use abstutil::WeightedUsizeChoice;
use control::ControlMap;
use driving::DrivingGoal;
use map_model::{BuildingID, BusRoute, BusRouteID, BusStopID, LaneID, Map, RoadID};
use std::collections::{BTreeSet, VecDeque};
@ -14,11 +13,11 @@ use {
impl Sim {
// TODO share the helpers for spawning specific parking spots and stuff?
pub fn run_until_done(&mut self, map: &Map, control_map: &ControlMap, callback: Box<Fn(&Sim)>) {
pub fn run_until_done(&mut self, map: &Map, callback: Box<Fn(&Sim)>) {
let mut benchmark = self.start_benchmark();
loop {
match panic::catch_unwind(panic::AssertUnwindSafe(|| {
self.step(&map, &control_map);
self.step(&map);
})) {
Ok(()) => {}
Err(err) => {
@ -43,7 +42,6 @@ impl Sim {
pub fn run_until_expectations_met(
&mut self,
map: &Map,
control_map: &ControlMap,
all_expectations: Vec<Event>,
time_limit: Tick,
) {
@ -53,7 +51,7 @@ impl Sim {
if expectations.is_empty() {
return;
}
for ev in self.step(&map, &control_map).into_iter() {
for ev in self.step(&map).into_iter() {
if ev == *expectations.front().unwrap() {
info!("At {}, met expectation {:?}", self.time, ev);
expectations.pop_front();

View File

@ -2,10 +2,9 @@
use abstutil;
use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
use control::{ControlMap, ControlStopSign, TurnPriority};
use dimensioned::si;
use kinematics;
use map_model::{IntersectionID, IntersectionType, Map, TurnID};
use map_model::{ControlStopSign, IntersectionID, IntersectionType, Map, TurnID, TurnPriority};
use std::collections::{BTreeMap, BTreeSet};
use view::WorldView;
use {AgentID, CarID, Event, PedestrianID, Tick, Time};
@ -95,21 +94,12 @@ impl IntersectionSimState {
}
}
pub fn step(
&mut self,
events: &mut Vec<Event>,
time: Tick,
map: &Map,
control_map: &ControlMap,
view: &WorldView,
) {
pub fn step(&mut self, events: &mut Vec<Event>, time: Tick, map: &Map, view: &WorldView) {
for i in self.intersections.iter_mut() {
match i {
IntersectionPolicy::StopSignPolicy(ref mut p) => {
p.step(events, time, map, control_map, view)
}
IntersectionPolicy::StopSignPolicy(ref mut p) => p.step(events, time, map, view),
IntersectionPolicy::TrafficSignalPolicy(ref mut p) => {
p.step(events, time, map, control_map, view)
p.step(events, time, map, view)
}
IntersectionPolicy::BorderPolicy => {}
}
@ -142,7 +132,7 @@ impl IntersectionSimState {
}
}
pub fn debug(&mut self, id: IntersectionID, control_map: &ControlMap) {
pub fn debug(&mut self, id: IntersectionID, map: &Map) {
if let Some(old) = self.debug {
match self.intersections.get_mut(old.0).unwrap() {
IntersectionPolicy::StopSignPolicy(ref mut p) => {
@ -159,11 +149,11 @@ impl IntersectionSimState {
match self.intersections.get_mut(id.0).unwrap() {
IntersectionPolicy::StopSignPolicy(ref mut p) => {
p.debug = true;
println!("{}", abstutil::to_json(&control_map.stop_signs[&id]));
println!("{}", abstutil::to_json(map.get_stop_sign(id)));
}
IntersectionPolicy::TrafficSignalPolicy(ref mut p) => {
p.debug = true;
println!("{}", abstutil::to_json(&control_map.traffic_signals[&id]));
println!("{}", abstutil::to_json(map.get_traffic_signal(id)));
}
IntersectionPolicy::BorderPolicy => {
println!("{} is a border", id);
@ -254,15 +244,8 @@ impl StopSign {
}).is_some()
}
fn step(
&mut self,
events: &mut Vec<Event>,
time: Tick,
map: &Map,
control_map: &ControlMap,
view: &WorldView,
) {
let ss = &control_map.stop_signs[&self.id];
fn step(&mut self, events: &mut Vec<Event>, time: Tick, map: &Map, view: &WorldView) {
let ss = map.get_stop_sign(self.id);
// If anybody is stopped, promote them.
// TODO retain() would rock
@ -342,15 +325,8 @@ impl TrafficSignal {
}
}
fn step(
&mut self,
events: &mut Vec<Event>,
time: Tick,
map: &Map,
control_map: &ControlMap,
view: &WorldView,
) {
let signal = &control_map.traffic_signals[&self.id];
fn step(&mut self, events: &mut Vec<Event>, time: Tick, map: &Map, view: &WorldView) {
let signal = map.get_traffic_signal(self.id);
let (cycle, _remaining_cycle_time) =
signal.current_cycle_and_remaining_time(time.as_time());

View File

@ -2,7 +2,6 @@
extern crate abstutil;
extern crate backtrace;
extern crate control;
#[macro_use]
extern crate derivative;
extern crate dimensioned;
@ -58,7 +57,7 @@ pub use events::Event;
pub use instrument::save_backtraces;
pub use kinematics::VehicleType;
pub use make::{
load, ABTest, ABTestResults, BorderSpawnOverTime, MapEdits, Neighborhood, NeighborhoodBuilder,
load, ABTest, ABTestResults, BorderSpawnOverTime, Neighborhood, NeighborhoodBuilder,
OriginDestination, Scenario, SeedParkedCars, SimFlags, SpawnOverTime,
};
use map_model::{BuildingID, LaneID};
@ -162,5 +161,4 @@ impl Cloneable for Neighborhood {}
impl Cloneable for NeighborhoodBuilder {}
impl Cloneable for Scenario {}
impl Cloneable for Tick {}
impl Cloneable for MapEdits {}
impl Cloneable for ABTest {}

View File

@ -1,41 +0,0 @@
use abstutil;
use control::{ControlStopSign, ControlTrafficSignal};
use map_model::{IntersectionID, RoadEdits};
use std::collections::BTreeMap;
// This has to live in sim, not map_model, because the control layer is between the two.
#[derive(Serialize, Deserialize, Clone)]
pub struct MapEdits {
pub edits_name: String,
pub map_name: String,
pub road_edits: RoadEdits,
pub stop_signs: BTreeMap<IntersectionID, ControlStopSign>,
pub traffic_signals: BTreeMap<IntersectionID, ControlTrafficSignal>,
}
impl MapEdits {
pub fn new() -> MapEdits {
MapEdits {
edits_name: "no_edits".to_string(),
map_name: "TODO".to_string(), // TODO er
road_edits: RoadEdits::new(),
stop_signs: BTreeMap::new(),
traffic_signals: BTreeMap::new(),
}
}
pub fn describe(&self) -> String {
format!(
"map edits \"{}\" ({} roads, {} stop signs, {} traffic signals",
self.edits_name,
self.road_edits.len(),
self.stop_signs.len(),
self.traffic_signals.len()
)
}
pub fn save(&self) {
abstutil::save_object("edits", &self.map_name, &self.edits_name, self);
}
}

View File

@ -1,7 +1,6 @@
use abstutil;
use control::ControlMap;
use map_model::Map;
use {MapEdits, Scenario, Sim, Tick};
use map_model::{Map, MapEdits};
use {Scenario, Sim, Tick};
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "sim_flags")]
@ -44,7 +43,7 @@ pub fn load(
flags: SimFlags,
savestate_every: Option<Tick>,
timer: &mut abstutil::Timer,
) -> (Map, ControlMap, Sim) {
) -> (Map, Sim) {
if flags.load.contains("data/save/") {
assert_eq!(flags.edits_name, "no_edits");
@ -54,7 +53,7 @@ pub fn load(
timer.stop("read sim savestate");
let edits: MapEdits = if sim.edits_name == "no_edits" {
MapEdits::new()
MapEdits::new(&sim.map_name)
} else {
abstutil::read_json(&format!(
"../data/edits/{}/{}.json",
@ -68,12 +67,11 @@ pub fn load(
timer,
).unwrap_or_else(|_| {
let map_path = format!("../data/raw_maps/{}.abst", sim.map_name);
Map::new(&map_path, edits.road_edits.clone(), timer)
Map::new(&map_path, edits, timer)
.expect(&format!("Couldn't load map from {}", map_path))
});
let control_map = ControlMap::new(&map, edits.stop_signs, edits.traffic_signals);
(map, control_map, sim)
(map, sim)
} else if flags.load.contains("data/scenarios/") {
info!("Seeding the simulation from scenario {}", flags.load);
let scenario: Scenario = abstutil::read_json(&flags.load).expect("loading scenario failed");
@ -88,10 +86,9 @@ pub fn load(
timer,
).unwrap_or_else(|_| {
let map_path = format!("../data/raw_maps/{}.abst", scenario.map_name);
Map::new(&map_path, edits.road_edits.clone(), timer)
Map::new(&map_path, edits, timer)
.expect(&format!("Couldn't load map from {}", map_path))
});
let control_map = ControlMap::new(&map, edits.stop_signs, edits.traffic_signals);
let mut sim = Sim::new(
&map,
// TODO or the scenario name if no run name
@ -100,7 +97,7 @@ pub fn load(
savestate_every,
);
scenario.instantiate(&mut sim, &map);
(map, control_map, sim)
(map, sim)
} else if flags.load.contains("data/raw_maps/") {
// TODO relative dir is brittle; match more cautiously
let map_name = flags
@ -110,30 +107,22 @@ pub fn load(
.to_string();
info!("Loading map {}", flags.load);
let edits = load_edits(&map_name, &flags);
let map = Map::new(&flags.load, edits.road_edits.clone(), timer)
let map = Map::new(&flags.load, edits, timer)
.expect(&format!("Couldn't load map from {}", flags.load));
let control_map = ControlMap::new(&map, edits.stop_signs, edits.traffic_signals);
timer.start("create sim");
let sim = Sim::new(&map, flags.run_name, flags.rng_seed, savestate_every);
timer.stop("create sim");
(map, control_map, sim)
(map, sim)
} else if flags.load.contains("data/maps/") {
assert_eq!(flags.edits_name, "no_edits");
info!("Loading map {}", flags.load);
let map: Map = abstutil::read_binary(&flags.load, timer)
.expect(&format!("Couldn't load map from {}", flags.load));
// TODO Bit sad to load edits to reconstitute ControlMap, but this is necessary right now
let edits: MapEdits = abstutil::read_json(&format!(
"../data/edits/{}/{}.json",
map.get_name(),
map.get_road_edits().edits_name
)).unwrap();
let control_map = ControlMap::new(&map, edits.stop_signs, edits.traffic_signals);
timer.start("create sim");
let sim = Sim::new(&map, flags.run_name, flags.rng_seed, savestate_every);
timer.stop("create sim");
(map, control_map, sim)
(map, sim)
} else {
panic!("Don't know how to load {}", flags.load);
}
@ -141,7 +130,7 @@ pub fn load(
fn load_edits(map_name: &str, flags: &SimFlags) -> MapEdits {
if flags.edits_name == "no_edits" {
return MapEdits::new();
return MapEdits::new(map_name);
}
if flags.edits_name.contains("data/") || flags.edits_name.contains(".json") {
panic!(

View File

@ -2,13 +2,11 @@
// it.
mod a_b_test;
mod edits;
mod load;
mod neighborhood;
mod scenario;
pub use self::a_b_test::{ABTest, ABTestResults};
pub use self::edits::MapEdits;
pub use self::load::{load, SimFlags};
pub use self::neighborhood::{Neighborhood, NeighborhoodBuilder};
pub use self::scenario::{

View File

@ -2,7 +2,6 @@
use abstutil;
use abstutil::Error;
use control::ControlMap;
use driving::DrivingSimState;
use instrument::capture_backtrace;
use intersections::IntersectionSimState;
@ -77,7 +76,7 @@ impl Sim {
transit_state: TransitSimState::new(),
time: Tick::zero(),
map_name: map.get_name().to_string(),
edits_name: map.get_road_edits().edits_name.to_string(),
edits_name: map.get_edits().edits_name.to_string(),
run_name,
savestate_every,
current_agent_for_debugging: None,
@ -144,13 +143,13 @@ impl Sim {
}
}
pub fn step(&mut self, map: &Map, control_map: &ControlMap) -> Vec<Event> {
pub fn step(&mut self, map: &Map) -> Vec<Event> {
// If there's an error, panic, so editor or headless will catch it, call dump_before_abort,
// and also do any other bail-out handling.
self.inner_step(map, control_map).unwrap()
self.inner_step(map).unwrap()
}
fn inner_step(&mut self, map: &Map, control_map: &ControlMap) -> Result<(Vec<Event>), Error> {
fn inner_step(&mut self, map: &Map) -> Result<(Vec<Event>), Error> {
let mut view = WorldView::new();
let mut events: Vec<Event> = Vec::new();
@ -237,7 +236,7 @@ impl Sim {
// Note that the intersection sees the WorldView BEFORE the updates that just happened this
// tick.
self.intersection_state
.step(&mut events, self.time, map, control_map, &view);
.step(&mut events, self.time, map, &view);
// Do this at the end of the step, so that tick 0 actually occurs and things can happen
// then.
@ -286,8 +285,8 @@ impl Sim {
self.driving_state.toggle_debug(id);
}
pub fn debug_intersection(&mut self, id: IntersectionID, control_map: &ControlMap) {
self.intersection_state.debug(id, control_map);
pub fn debug_intersection(&mut self, id: IntersectionID, map: &Map) {
self.intersection_state.debug(id, map);
}
pub fn save(&self) -> String {

View File

@ -35,12 +35,12 @@ pub fn run(t: &mut TestRunner) {
Box::new(|_| {
let map1 = map_model::Map::new(
"../data/raw_maps/montlake.abst",
map_model::RoadEdits::new(),
map_model::MapEdits::new("montlake"),
&mut abstutil::Timer::new("raw to map"),
).unwrap();
let map2 = map_model::Map::new(
"../data/raw_maps/montlake.abst",
map_model::RoadEdits::new(),
map_model::MapEdits::new("montlake"),
&mut abstutil::Timer::new("raw to map"),
).unwrap();

View File

@ -8,7 +8,7 @@ pub fn run(t: &mut TestRunner) {
t.run_slow(
"park_on_goal_st",
Box::new(|h| {
let (map, control_map, mut sim) = sim::load(
let (map, mut sim) = sim::load(
sim::SimFlags::synthetic_test("parking_test", "park_on_goal_st"),
None,
&mut Timer::new("setup test"),
@ -28,21 +28,20 @@ pub fn run(t: &mut TestRunner) {
sim.run_until_expectations_met(
&map,
&control_map,
vec![sim::Event::CarReachedParkingSpot(
car,
sim::ParkingSpot::new(north_parking, 4),
)],
sim::Tick::from_minutes(2),
);
sim.run_until_done(&map, &control_map, Box::new(|_sim| {}));
sim.run_until_done(&map, Box::new(|_sim| {}));
}),
);
t.run_slow(
"wander_around_for_parking",
Box::new(|h| {
let (map, control_map, mut sim) = sim::load(
let (map, mut sim) = sim::load(
sim::SimFlags::synthetic_test("parking_test", "wander_around_for_parking"),
None,
&mut Timer::new("setup test"),
@ -62,14 +61,13 @@ pub fn run(t: &mut TestRunner) {
sim.run_until_expectations_met(
&map,
&control_map,
vec![sim::Event::CarReachedParkingSpot(
car,
sim::ParkingSpot::new(south_parking, 0),
)],
sim::Tick::from_minutes(2),
);
sim.run_until_done(&map, &control_map, Box::new(|_sim| {}));
sim.run_until_done(&map, Box::new(|_sim| {}));
}),
);
}

View File

@ -6,14 +6,14 @@ pub fn run(t: &mut TestRunner) {
t.run_slow(
"small_spawn_completes",
Box::new(|h| {
let (map, control_map, mut sim) = sim::load(
let (map, mut sim) = sim::load(
sim::SimFlags::for_test("aorta_model_completes"),
Some(sim::Tick::from_seconds(30)),
&mut Timer::new("setup test"),
);
sim.small_spawn(&map);
h.setup_done(&sim);
sim.run_until_done(&map, &control_map, Box::new(|_sim| {}));
sim.run_until_done(&map, Box::new(|_sim| {}));
}),
);
}

View File

@ -6,7 +6,7 @@ pub fn run(t: &mut TestRunner) {
t.run_slow(
"serialization",
Box::new(|_| {
let (map, _, mut sim) = sim::load(
let (map, mut sim) = sim::load(
sim::SimFlags::for_test("serialization"),
None,
&mut Timer::new("setup test"),
@ -24,7 +24,7 @@ pub fn run(t: &mut TestRunner) {
"from_scratch",
Box::new(|_| {
println!("Creating two simulations");
let (map, control_map, mut sim1) = sim::load(
let (map, mut sim1) = sim::load(
sim::SimFlags::for_test("from_scratch_1"),
None,
&mut Timer::new("setup test"),
@ -42,8 +42,8 @@ pub fn run(t: &mut TestRunner) {
sim2.save()
);
}
sim1.step(&map, &control_map);
sim2.step(&map, &control_map);
sim1.step(&map);
sim2.step(&map);
}
}),
);
@ -52,7 +52,7 @@ pub fn run(t: &mut TestRunner) {
"with_savestating",
Box::new(|_| {
println!("Creating two simulations");
let (map, control_map, mut sim1) = sim::load(
let (map, mut sim1) = sim::load(
sim::SimFlags::for_test("with_savestating_1"),
None,
&mut Timer::new("setup test"),
@ -62,8 +62,8 @@ pub fn run(t: &mut TestRunner) {
sim2.small_spawn(&map);
for _ in 1..600 {
sim1.step(&map, &control_map);
sim2.step(&map, &control_map);
sim1.step(&map);
sim2.step(&map);
}
if sim1 != sim2 {
@ -77,7 +77,7 @@ pub fn run(t: &mut TestRunner) {
let sim1_save = sim1.save();
for _ in 1..60 {
sim1.step(&map, &control_map);
sim1.step(&map);
}
if sim1 == sim2 {

View File

@ -7,7 +7,7 @@ pub fn run(t: &mut TestRunner) {
t.run_slow(
"bus_reaches_stops",
Box::new(|h| {
let (map, control_map, mut sim) = sim::load(
let (map, mut sim) = sim::load(
SimFlags::for_test("bus_reaches_stops"),
Some(Tick::from_seconds(30)),
&mut Timer::new("setup test"),
@ -24,20 +24,15 @@ pub fn run(t: &mut TestRunner) {
expectations.push(Event::BusDepartedFromStop(bus, *stop));
}
sim.run_until_expectations_met(
&map,
&control_map,
expectations,
Tick::from_minutes(10),
);
sim.run_until_done(&map, &control_map, Box::new(|_sim| {}));
sim.run_until_expectations_met(&map, expectations, Tick::from_minutes(10));
sim.run_until_done(&map, Box::new(|_sim| {}));
}),
);
t.run_slow(
"ped_uses_bus",
Box::new(|h| {
let (map, control_map, mut sim) = sim::load(
let (map, mut sim) = sim::load(
SimFlags::for_test("ped_uses_bus"),
Some(Tick::from_seconds(30)),
&mut Timer::new("setup test"),
@ -56,7 +51,6 @@ pub fn run(t: &mut TestRunner) {
sim.run_until_expectations_met(
&map,
&control_map,
vec![
sim::Event::PedReachedBusStop(ped, ped_stop1),
sim::Event::BusArrivedAtStop(bus, ped_stop1),