mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
bundling all map edits together
This commit is contained in:
parent
bbfe00ce63
commit
7b718b4621
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,7 +3,7 @@
|
|||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
editor/editor_state
|
editor/editor_state
|
||||||
editor/road_edits.json
|
editor/map_edits.json
|
||||||
|
|
||||||
data/input/*
|
data/input/*
|
||||||
data/maps/*.abst
|
data/maps/*.abst
|
||||||
|
@ -22,7 +22,11 @@ pub struct ControlMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ControlMap {
|
impl ControlMap {
|
||||||
pub fn new(map: &Map) -> ControlMap {
|
pub fn new(
|
||||||
|
map: &Map,
|
||||||
|
stop_signs: &BTreeMap<IntersectionID, ModifiedStopSign>,
|
||||||
|
traffic_signals: &BTreeMap<IntersectionID, ModifiedTrafficSignal>,
|
||||||
|
) -> ControlMap {
|
||||||
let mut ctrl = ControlMap {
|
let mut ctrl = ControlMap {
|
||||||
traffic_signals: HashMap::new(),
|
traffic_signals: HashMap::new(),
|
||||||
stop_signs: HashMap::new(),
|
stop_signs: HashMap::new(),
|
||||||
@ -38,11 +42,18 @@ impl ControlMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i, s) in traffic_signals {
|
||||||
|
ctrl.traffic_signals.get_mut(i).unwrap().load_savestate(s);
|
||||||
|
}
|
||||||
|
for (i, s) in stop_signs {
|
||||||
|
ctrl.stop_signs.get_mut(i).unwrap().load_savestate(s);
|
||||||
|
}
|
||||||
|
|
||||||
ctrl
|
ctrl
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_traffic_signals_savestate(&self) -> HashMap<IntersectionID, ModifiedTrafficSignal> {
|
pub fn get_traffic_signals_savestate(&self) -> BTreeMap<IntersectionID, ModifiedTrafficSignal> {
|
||||||
let mut h = HashMap::new();
|
let mut h = BTreeMap::new();
|
||||||
for (i, s) in &self.traffic_signals {
|
for (i, s) in &self.traffic_signals {
|
||||||
if let Some(state) = s.get_savestate() {
|
if let Some(state) = s.get_savestate() {
|
||||||
h.insert(*i, state);
|
h.insert(*i, state);
|
||||||
@ -51,8 +62,8 @@ impl ControlMap {
|
|||||||
h
|
h
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_stop_signs_savestate(&self) -> HashMap<IntersectionID, ModifiedStopSign> {
|
pub fn get_stop_signs_savestate(&self) -> BTreeMap<IntersectionID, ModifiedStopSign> {
|
||||||
let mut h = HashMap::new();
|
let mut h = BTreeMap::new();
|
||||||
for (i, s) in &self.stop_signs {
|
for (i, s) in &self.stop_signs {
|
||||||
if let Some(state) = s.get_savestate() {
|
if let Some(state) = s.get_savestate() {
|
||||||
h.insert(*i, state);
|
h.insert(*i, state);
|
||||||
@ -60,19 +71,6 @@ impl ControlMap {
|
|||||||
}
|
}
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_savestate(
|
|
||||||
&mut self,
|
|
||||||
traffic_signals: &HashMap<IntersectionID, ModifiedTrafficSignal>,
|
|
||||||
stop_signs: &HashMap<IntersectionID, ModifiedStopSign>,
|
|
||||||
) {
|
|
||||||
for (i, s) in traffic_signals {
|
|
||||||
self.traffic_signals.get_mut(i).unwrap().load_savestate(s);
|
|
||||||
}
|
|
||||||
for (i, s) in stop_signs {
|
|
||||||
self.stop_signs.get_mut(i).unwrap().load_savestate(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// General problem: TurnIDs change as code does. Serialized state is kinda tied to code version.
|
// General problem: TurnIDs change as code does. Serialized state is kinda tied to code version.
|
||||||
|
@ -257,3 +257,23 @@ current TreeMenu:
|
|||||||
|
|
||||||
|
|
||||||
Back up and think about ideal for these background controls...
|
Back up and think about ideal for these background controls...
|
||||||
|
|
||||||
|
## Managing different map edits
|
||||||
|
|
||||||
|
Should be simple -- I want to bundle together map edits as named things, to
|
||||||
|
prep for A/B tests. But loading a different set of edits could be kind of
|
||||||
|
tough...
|
||||||
|
|
||||||
|
- new control map state has to propagate to intersection editors.
|
||||||
|
- easy fix: pass them mut ref from control map every tick. then just have to reload control map.
|
||||||
|
- road edits have to propogate
|
||||||
|
- theres a way to do that live right now, but it's kind of brittle and funky. probably safer to load from scratch.
|
||||||
|
- but then have to reload things like steepness visualizer plugin... actually, just that, seemingly.
|
||||||
|
- er, but also the hider plugin -- it holds onto laneIDs, which may change!
|
||||||
|
|
||||||
|
Alright, I think this is the sequence of things to do:
|
||||||
|
|
||||||
|
1) make a few plugins less stateful anyway, by taking refs to map/control map stuff instead of caching stuff. thats useful regardless.
|
||||||
|
- but wait, then road editor kind of cant work, because mut borrow edits from map while holding immutable lane/road refs. theyre really indep things, so cant store together.
|
||||||
|
2) make it possible to completely reload UI and everything from scratch, from a plugin. rationale: it'd be nice to switch maps from inside the editor anyway. not necessary, but useful.
|
||||||
|
3) make road edits propogate correctly, and somehow have a strategy for ensuring nothing is forgotten. impl today is VERY incomplete.
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
use control::ControlMap;
|
use control::ControlMap;
|
||||||
use ezgui::UserInput;
|
use ezgui::UserInput;
|
||||||
use map_model::{EditReason, Edits, LaneID, LaneType, Map};
|
use map_model::{EditReason, LaneID, LaneType, Map, RoadEdits};
|
||||||
use objects::{EDIT_MAP, ID};
|
use objects::{EDIT_MAP, ID};
|
||||||
use piston::input::Key;
|
use piston::input::Key;
|
||||||
use plugins::Colorizer;
|
use plugins::Colorizer;
|
||||||
use render::DrawMap;
|
use render::DrawMap;
|
||||||
use sim::Sim;
|
use sim::Sim;
|
||||||
|
|
||||||
pub enum RoadEditor {
|
pub struct RoadEditor {
|
||||||
Inactive(Edits),
|
edits: RoadEdits,
|
||||||
Active(Edits),
|
active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoadEditor {
|
impl RoadEditor {
|
||||||
pub fn new(edits: Edits) -> RoadEditor {
|
pub fn new(edits: RoadEdits) -> RoadEditor {
|
||||||
RoadEditor::Inactive(edits)
|
RoadEditor {
|
||||||
|
edits,
|
||||||
|
active: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event(
|
pub fn event(
|
||||||
@ -26,63 +29,60 @@ impl RoadEditor {
|
|||||||
control_map: &ControlMap,
|
control_map: &ControlMap,
|
||||||
sim: &mut Sim,
|
sim: &mut Sim,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut new_state: Option<RoadEditor> = None;
|
// 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;
|
let mut changed: Option<(LaneID, LaneType)> = None;
|
||||||
|
|
||||||
match self {
|
if !self.active && selected.is_none() {
|
||||||
RoadEditor::Inactive(edits) => match selected {
|
if input.unimportant_key_pressed(Key::E, EDIT_MAP, "Start editing roads") {
|
||||||
None => {
|
self.active = true;
|
||||||
if input.unimportant_key_pressed(Key::E, EDIT_MAP, "Start editing roads") {
|
}
|
||||||
// TODO cloning edits sucks! want to consume self
|
}
|
||||||
new_state = Some(RoadEditor::Active(edits.clone()));
|
if self.active {
|
||||||
}
|
if input.key_pressed(Key::Return, "stop editing roads") {
|
||||||
}
|
self.active = false;
|
||||||
_ => {}
|
} else if let Some(ID::Lane(id)) = selected {
|
||||||
},
|
let lane = map.get_l(id);
|
||||||
RoadEditor::Active(edits) => {
|
let road = map.get_r(lane.parent);
|
||||||
if input.key_pressed(Key::Return, "stop editing roads") {
|
let reason = EditReason::BasemapWrong; // TODO be able to choose
|
||||||
new_state = Some(RoadEditor::Inactive(edits.clone()));
|
|
||||||
} else if let Some(ID::Lane(id)) = selected {
|
|
||||||
let lane = map.get_l(id);
|
|
||||||
let road = map.get_r(lane.parent);
|
|
||||||
let reason = EditReason::BasemapWrong; // TODO be able to choose
|
|
||||||
|
|
||||||
if lane.lane_type != LaneType::Sidewalk {
|
if lane.lane_type != LaneType::Sidewalk {
|
||||||
if lane.lane_type != LaneType::Driving
|
if lane.lane_type != LaneType::Driving
|
||||||
&& input.key_pressed(Key::D, "make this a driving lane")
|
&& input.key_pressed(Key::D, "make this a driving lane")
|
||||||
|
{
|
||||||
|
if self
|
||||||
|
.edits
|
||||||
|
.change_lane_type(reason, road, lane, LaneType::Driving)
|
||||||
{
|
{
|
||||||
if edits.change_lane_type(reason, road, lane, LaneType::Driving) {
|
changed = Some((lane.id, LaneType::Driving));
|
||||||
changed = Some((lane.id, LaneType::Driving));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if lane.lane_type != LaneType::Parking
|
}
|
||||||
&& input.key_pressed(Key::P, "make this a parking lane")
|
if lane.lane_type != LaneType::Parking
|
||||||
|
&& input.key_pressed(Key::P, "make this a parking lane")
|
||||||
|
{
|
||||||
|
if self
|
||||||
|
.edits
|
||||||
|
.change_lane_type(reason, road, lane, LaneType::Parking)
|
||||||
{
|
{
|
||||||
if edits.change_lane_type(reason, road, lane, LaneType::Parking) {
|
changed = Some((lane.id, LaneType::Parking));
|
||||||
changed = Some((lane.id, LaneType::Parking));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if lane.lane_type != LaneType::Biking
|
}
|
||||||
&& input.key_pressed(Key::B, "make this a bike lane")
|
if lane.lane_type != LaneType::Biking
|
||||||
|
&& input.key_pressed(Key::B, "make this a bike lane")
|
||||||
|
{
|
||||||
|
if self
|
||||||
|
.edits
|
||||||
|
.change_lane_type(reason, road, lane, LaneType::Biking)
|
||||||
{
|
{
|
||||||
if edits.change_lane_type(reason, road, lane, LaneType::Biking) {
|
changed = Some((lane.id, LaneType::Biking));
|
||||||
changed = Some((lane.id, LaneType::Biking));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if input.key_pressed(Key::Backspace, "delete this lane") {
|
}
|
||||||
if edits.delete_lane(road, lane) {
|
if input.key_pressed(Key::Backspace, "delete this lane") {
|
||||||
warn!(
|
if self.edits.delete_lane(road, lane) {
|
||||||
"Have to reload the map from scratch to pick up this change!"
|
warn!("Have to reload the map from scratch to pick up this change!");
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if let Some(s) = new_state {
|
|
||||||
*self = s;
|
|
||||||
}
|
}
|
||||||
if let Some((id, new_type)) = changed {
|
if let Some((id, new_type)) = changed {
|
||||||
let intersections = map.get_l(id).intersections();
|
let intersections = map.get_l(id).intersections();
|
||||||
@ -114,17 +114,11 @@ impl RoadEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
self.active
|
||||||
RoadEditor::Inactive(_) => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_edits(&self) -> &Edits {
|
pub fn get_edits(&self) -> &RoadEdits {
|
||||||
match self {
|
&self.edits
|
||||||
RoadEditor::Inactive(edits) => edits,
|
|
||||||
RoadEditor::Active(edits) => edits,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
use abstutil;
|
use abstutil;
|
||||||
use colors::{ColorScheme, Colors};
|
use colors::{ColorScheme, Colors};
|
||||||
use control::ControlMap;
|
use control::ControlMap;
|
||||||
use control::{ModifiedStopSign, ModifiedTrafficSignal};
|
|
||||||
use ezgui::{Canvas, EventLoopMode, GfxCtx, Text, ToggleableLayer, UserInput, BOTTOM_LEFT, GUI};
|
use ezgui::{Canvas, EventLoopMode, GfxCtx, Text, ToggleableLayer, UserInput, BOTTOM_LEFT, GUI};
|
||||||
use flame;
|
use flame;
|
||||||
use graphics::types::Color;
|
use graphics::types::Color;
|
||||||
@ -37,8 +36,7 @@ use plugins::warp::WarpState;
|
|||||||
use plugins::Colorizer;
|
use plugins::Colorizer;
|
||||||
use render::{DrawMap, RenderOptions};
|
use render::{DrawMap, RenderOptions};
|
||||||
use sim;
|
use sim;
|
||||||
use sim::Sim;
|
use sim::{MapEdits, Sim};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
// TODO ideally these would be tuned kind of dynamically based on rendering speed
|
// TODO ideally these would be tuned kind of dynamically based on rendering speed
|
||||||
@ -77,13 +75,12 @@ impl UIWrapper {
|
|||||||
let logs = DisplayLogs::new();
|
let logs = DisplayLogs::new();
|
||||||
|
|
||||||
flame::start("setup");
|
flame::start("setup");
|
||||||
let (map, edits, control_map, sim) = sim::load(
|
let (map, control_map, sim) = sim::load(
|
||||||
load,
|
load,
|
||||||
scenario_name,
|
scenario_name,
|
||||||
rng_seed,
|
rng_seed,
|
||||||
Some(sim::Tick::from_seconds(30)),
|
Some(sim::Tick::from_seconds(30)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let extra_shapes = if let Some(path) = kml {
|
let extra_shapes = if let Some(path) = kml {
|
||||||
kml::load(&path, &map.get_gps_bounds()).expect("Couldn't load extra KML shapes")
|
kml::load(&path, &map.get_gps_bounds()).expect("Couldn't load extra KML shapes")
|
||||||
} else {
|
} else {
|
||||||
@ -98,6 +95,7 @@ impl UIWrapper {
|
|||||||
flame::dump_stdout();
|
flame::dump_stdout();
|
||||||
|
|
||||||
let steepness_viz = SteepnessVisualizer::new(&map);
|
let steepness_viz = SteepnessVisualizer::new(&map);
|
||||||
|
let road_editor = RoadEditor::new(map.get_road_edits().clone());
|
||||||
|
|
||||||
let mut ui = UI {
|
let mut ui = UI {
|
||||||
// TODO organize this by section
|
// TODO organize this by section
|
||||||
@ -107,6 +105,7 @@ impl UIWrapper {
|
|||||||
sim,
|
sim,
|
||||||
|
|
||||||
steepness_viz,
|
steepness_viz,
|
||||||
|
road_editor,
|
||||||
sim_ctrl: SimController::new(),
|
sim_ctrl: SimController::new(),
|
||||||
|
|
||||||
layers: ToggleableLayers::new(),
|
layers: ToggleableLayers::new(),
|
||||||
@ -123,7 +122,6 @@ impl UIWrapper {
|
|||||||
osm_classifier: OsmClassifier::new(),
|
osm_classifier: OsmClassifier::new(),
|
||||||
traffic_signal_editor: TrafficSignalEditor::new(),
|
traffic_signal_editor: TrafficSignalEditor::new(),
|
||||||
stop_sign_editor: StopSignEditor::new(),
|
stop_sign_editor: StopSignEditor::new(),
|
||||||
road_editor: RoadEditor::new(edits),
|
|
||||||
color_picker: ColorPicker::new(),
|
color_picker: ColorPicker::new(),
|
||||||
geom_validator: Validator::new(),
|
geom_validator: Validator::new(),
|
||||||
turn_cycler: TurnCyclerState::new(),
|
turn_cycler: TurnCyclerState::new(),
|
||||||
@ -143,8 +141,6 @@ impl UIWrapper {
|
|||||||
ui.canvas.cam_x = state.cam_x;
|
ui.canvas.cam_x = state.cam_x;
|
||||||
ui.canvas.cam_y = state.cam_y;
|
ui.canvas.cam_y = state.cam_y;
|
||||||
ui.canvas.cam_zoom = state.cam_zoom;
|
ui.canvas.cam_zoom = state.cam_zoom;
|
||||||
ui.control_map
|
|
||||||
.load_savestate(&state.traffic_signals, &state.stop_signs);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Couldn't load editor_state or it's for a different map, so just centering initial view");
|
warn!("Couldn't load editor_state or it's for a different map, so just centering initial view");
|
||||||
@ -384,15 +380,21 @@ impl UI {
|
|||||||
cam_x: self.canvas.cam_x,
|
cam_x: self.canvas.cam_x,
|
||||||
cam_y: self.canvas.cam_y,
|
cam_y: self.canvas.cam_y,
|
||||||
cam_zoom: self.canvas.cam_zoom,
|
cam_zoom: self.canvas.cam_zoom,
|
||||||
traffic_signals: self.control_map.get_traffic_signals_savestate(),
|
|
||||||
stop_signs: self.control_map.get_stop_signs_savestate(),
|
|
||||||
};
|
};
|
||||||
// TODO maybe make state line up with the map, so loading from a new map doesn't break
|
// TODO maybe make state line up with the map, so loading from a new map doesn't break
|
||||||
abstutil::write_json("editor_state", &state).expect("Saving editor_state failed");
|
abstutil::write_json("editor_state", &state).expect("Saving editor_state failed");
|
||||||
abstutil::write_json("color_scheme", &self.cs).expect("Saving color_scheme failed");
|
abstutil::write_json("color_scheme", &self.cs).expect("Saving color_scheme failed");
|
||||||
abstutil::write_json("road_edits.json", self.road_editor.get_edits())
|
abstutil::write_json(
|
||||||
.expect("Saving road_edits.json failed");
|
"map_edits.json",
|
||||||
info!("Saved editor_state, color_scheme, and road_edits.json");
|
&MapEdits {
|
||||||
|
edits_name: "nameless".to_string(),
|
||||||
|
map_name: self.map.get_name().to_string(),
|
||||||
|
road_edits: self.road_editor.get_edits().clone(),
|
||||||
|
stop_signs: self.control_map.get_stop_signs_savestate(),
|
||||||
|
traffic_signals: self.control_map.get_traffic_signals_savestate(),
|
||||||
|
},
|
||||||
|
).expect("Saving map_edits.json failed");
|
||||||
|
info!("Saved editor_state, color_scheme, and map_edits.json");
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,9 +540,6 @@ pub struct EditorState {
|
|||||||
pub cam_x: f64,
|
pub cam_x: f64,
|
||||||
pub cam_y: f64,
|
pub cam_y: f64,
|
||||||
pub cam_zoom: f64,
|
pub cam_zoom: f64,
|
||||||
|
|
||||||
pub traffic_signals: HashMap<IntersectionID, ModifiedTrafficSignal>,
|
|
||||||
pub stop_signs: HashMap<IntersectionID, ModifiedStopSign>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ToggleableLayers {
|
pub struct ToggleableLayers {
|
||||||
|
@ -44,7 +44,7 @@ fn main() {
|
|||||||
log::set_max_level(LevelFilter::Debug);
|
log::set_max_level(LevelFilter::Debug);
|
||||||
log::set_logger(&LOG_ADAPTER).unwrap();
|
log::set_logger(&LOG_ADAPTER).unwrap();
|
||||||
|
|
||||||
let (map, _, control_map, mut sim) = sim::load(
|
let (map, control_map, mut sim) = sim::load(
|
||||||
flags.load.clone(),
|
flags.load.clone(),
|
||||||
flags.scenario_name,
|
flags.scenario_name,
|
||||||
flags.rng_seed,
|
flags.rng_seed,
|
||||||
|
@ -4,14 +4,14 @@ use {Lane, LaneType, Road, RoadID};
|
|||||||
// TODO bring in the intersection modifications from the control crate here. for now, road edits
|
// 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?
|
// are here, since map construction maybe needs to know these?
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Edits {
|
pub struct RoadEdits {
|
||||||
// TODO detect when we wind up editing back to the original thing
|
// TODO detect when we wind up editing back to the original thing
|
||||||
pub(crate) roads: BTreeMap<RoadID, RoadEdit>,
|
pub(crate) roads: BTreeMap<RoadID, RoadEdit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Edits {
|
impl RoadEdits {
|
||||||
pub fn new() -> Edits {
|
pub fn new() -> RoadEdits {
|
||||||
Edits {
|
RoadEdits {
|
||||||
roads: BTreeMap::new(),
|
roads: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ mod turn;
|
|||||||
pub use area::{Area, AreaID, AreaType};
|
pub use area::{Area, AreaID, AreaType};
|
||||||
pub use building::{Building, BuildingID, FrontPath};
|
pub use building::{Building, BuildingID, FrontPath};
|
||||||
pub use bus_stop::{BusRoute, BusStop, BusStopID};
|
pub use bus_stop::{BusRoute, BusStop, BusStopID};
|
||||||
pub use edits::{EditReason, Edits};
|
pub use edits::{EditReason, RoadEdits};
|
||||||
pub use intersection::{Intersection, IntersectionID};
|
pub use intersection::{Intersection, IntersectionID};
|
||||||
pub use lane::{Lane, LaneID, LaneType, PARKING_SPOT_LENGTH};
|
pub use lane::{Lane, LaneID, LaneType, PARKING_SPOT_LENGTH};
|
||||||
pub use map::Map;
|
pub use map::Map;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use edits::Edits;
|
use edits::RoadEdits;
|
||||||
use lane::LaneType;
|
use lane::LaneType;
|
||||||
use raw_data;
|
use raw_data;
|
||||||
use road::RoadID;
|
use road::RoadID;
|
||||||
@ -75,7 +75,7 @@ impl LaneSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_lane_specs(r: &raw_data::Road, id: RoadID, edits: &Edits) -> Vec<LaneSpec> {
|
pub(crate) fn get_lane_specs(r: &raw_data::Road, id: RoadID, edits: &RoadEdits) -> Vec<LaneSpec> {
|
||||||
let (side1_types, side2_types) = if let Some(e) = edits.roads.get(&id) {
|
let (side1_types, side2_types) = if let Some(e) = edits.roads.get(&id) {
|
||||||
info!("Using edits for {}", id);
|
info!("Using edits for {}", id);
|
||||||
(e.forwards_lanes.clone(), e.backwards_lanes.clone())
|
(e.forwards_lanes.clone(), e.backwards_lanes.clone())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
use abstutil;
|
use abstutil;
|
||||||
use edits::Edits;
|
use edits::RoadEdits;
|
||||||
use flame;
|
use flame;
|
||||||
use geom::{Bounds, HashablePt2D, PolyLine, Pt2D};
|
use geom::{Bounds, HashablePt2D, PolyLine, Pt2D};
|
||||||
use make;
|
use make;
|
||||||
@ -30,10 +30,11 @@ pub struct Map {
|
|||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
|
|
||||||
name: String,
|
name: String,
|
||||||
|
road_edits: RoadEdits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
pub fn new(path: &str, edits: &Edits) -> Result<Map, Error> {
|
pub fn new(path: &str, road_edits: RoadEdits) -> Result<Map, Error> {
|
||||||
// TODO I think I want something a bit different than flame:
|
// TODO I think I want something a bit different than flame:
|
||||||
// - Print as each phase occurs
|
// - Print as each phase occurs
|
||||||
// - Print with nicely formatted durations
|
// - Print with nicely formatted durations
|
||||||
@ -48,14 +49,15 @@ impl Map {
|
|||||||
.into_string()
|
.into_string()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
data,
|
data,
|
||||||
edits,
|
road_edits,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_from_raw(name: String, data: raw_data::Map, edits: &Edits) -> Map {
|
pub fn create_from_raw(name: String, data: raw_data::Map, road_edits: RoadEdits) -> Map {
|
||||||
let bounds = data.get_gps_bounds();
|
let bounds = data.get_gps_bounds();
|
||||||
let mut m = Map {
|
let mut m = Map {
|
||||||
name,
|
name,
|
||||||
|
road_edits,
|
||||||
bounds,
|
bounds,
|
||||||
roads: Vec::new(),
|
roads: Vec::new(),
|
||||||
lanes: Vec::new(),
|
lanes: Vec::new(),
|
||||||
@ -108,7 +110,7 @@ impl Map {
|
|||||||
let i2 = pt_to_intersection[&HashablePt2D::from(road_center_pts.last_pt())];
|
let i2 = pt_to_intersection[&HashablePt2D::from(road_center_pts.last_pt())];
|
||||||
|
|
||||||
// TODO move this to make/lanes.rs too
|
// TODO move this to make/lanes.rs too
|
||||||
for lane in make::get_lane_specs(r, road_id, edits) {
|
for lane in make::get_lane_specs(r, road_id, &m.road_edits) {
|
||||||
let id = LaneID(counter);
|
let id = LaneID(counter);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
|
||||||
@ -394,6 +396,10 @@ impl Map {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_road_edits(&self) -> &RoadEdits {
|
||||||
|
&self.road_edits
|
||||||
|
}
|
||||||
|
|
||||||
pub fn all_bus_stops(&self) -> &BTreeMap<BusStopID, BusStop> {
|
pub fn all_bus_stops(&self) -> &BTreeMap<BusStopID, BusStop> {
|
||||||
&self.bus_stops
|
&self.bus_stops
|
||||||
}
|
}
|
||||||
|
25
sim/src/edits.rs
Normal file
25
sim/src/edits.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use control::{ModifiedStopSign, ModifiedTrafficSignal};
|
||||||
|
use map_model::{IntersectionID, RoadEdits};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct MapEdits {
|
||||||
|
pub edits_name: String,
|
||||||
|
pub map_name: String,
|
||||||
|
|
||||||
|
pub road_edits: RoadEdits,
|
||||||
|
pub stop_signs: BTreeMap<IntersectionID, ModifiedStopSign>,
|
||||||
|
pub traffic_signals: BTreeMap<IntersectionID, ModifiedTrafficSignal>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapEdits {
|
||||||
|
pub fn new() -> MapEdits {
|
||||||
|
MapEdits {
|
||||||
|
edits_name: "unnamed".to_string(),
|
||||||
|
map_name: "TODO".to_string(), // TODO er
|
||||||
|
road_edits: RoadEdits::new(),
|
||||||
|
stop_signs: BTreeMap::new(),
|
||||||
|
traffic_signals: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,10 @@ use abstutil;
|
|||||||
use control::ControlMap;
|
use control::ControlMap;
|
||||||
use flame;
|
use flame;
|
||||||
use geom::Polygon;
|
use geom::Polygon;
|
||||||
use map_model::{BuildingID, BusRoute, BusStopID, Edits, LaneID, Map};
|
use map_model::{BuildingID, BusRoute, BusStopID, LaneID, Map};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use {CarID, Event, PedestrianID, RouteID, Scenario, Sim, Tick};
|
use {CarID, Event, MapEdits, PedestrianID, RouteID, Scenario, Sim, Tick};
|
||||||
|
|
||||||
// Convenience method to setup everything.
|
// Convenience method to setup everything.
|
||||||
pub fn load(
|
pub fn load(
|
||||||
@ -13,8 +13,9 @@ pub fn load(
|
|||||||
scenario_name: String,
|
scenario_name: String,
|
||||||
rng_seed: Option<u8>,
|
rng_seed: Option<u8>,
|
||||||
savestate_every: Option<Tick>,
|
savestate_every: Option<Tick>,
|
||||||
) -> (Map, Edits, ControlMap, Sim) {
|
) -> (Map, ControlMap, Sim) {
|
||||||
let edits: Edits = abstutil::read_json("road_edits.json").unwrap_or(Edits::new());
|
// TODO read a specific one
|
||||||
|
let edits: MapEdits = abstutil::read_json("map_edits.json").unwrap_or(MapEdits::new());
|
||||||
|
|
||||||
if input.contains("data/save/") {
|
if input.contains("data/save/") {
|
||||||
info!("Resuming from {}", input);
|
info!("Resuming from {}", input);
|
||||||
@ -23,17 +24,17 @@ pub fn load(
|
|||||||
flame::end("read sim savestate");
|
flame::end("read sim savestate");
|
||||||
// TODO assuming the relative path :(
|
// TODO assuming the relative path :(
|
||||||
let map_path = format!("../data/maps/{}.abst", sim.map_name);
|
let map_path = format!("../data/maps/{}.abst", sim.map_name);
|
||||||
let map =
|
let map = Map::new(&map_path, edits.road_edits.clone())
|
||||||
Map::new(&map_path, &edits).expect(&format!("Couldn't load map from {}", map_path));
|
.expect(&format!("Couldn't load map from {}", map_path));
|
||||||
let control_map = ControlMap::new(&map);
|
let control_map = ControlMap::new(&map, &edits.stop_signs, &edits.traffic_signals);
|
||||||
(map, edits, control_map, sim)
|
(map, control_map, sim)
|
||||||
} else if input.contains("data/scenarios/") {
|
} else if input.contains("data/scenarios/") {
|
||||||
info!("Seeding the simulation from scenario {}", input);
|
info!("Seeding the simulation from scenario {}", input);
|
||||||
let scenario: Scenario = abstutil::read_json(&input).expect("loading scenario failed");
|
let scenario: Scenario = abstutil::read_json(&input).expect("loading scenario failed");
|
||||||
let map_path = format!("../data/maps/{}.abst", scenario.map_name);
|
let map_path = format!("../data/maps/{}.abst", scenario.map_name);
|
||||||
let map =
|
let map = Map::new(&map_path, edits.road_edits.clone())
|
||||||
Map::new(&map_path, &edits).expect(&format!("Couldn't load map from {}", map_path));
|
.expect(&format!("Couldn't load map from {}", map_path));
|
||||||
let control_map = ControlMap::new(&map);
|
let control_map = ControlMap::new(&map, &edits.stop_signs, &edits.traffic_signals);
|
||||||
let mut sim = Sim::new(
|
let mut sim = Sim::new(
|
||||||
&map,
|
&map,
|
||||||
scenario.scenario_name.clone(),
|
scenario.scenario_name.clone(),
|
||||||
@ -41,15 +42,15 @@ pub fn load(
|
|||||||
savestate_every,
|
savestate_every,
|
||||||
);
|
);
|
||||||
scenario.instantiate(&mut sim, &map);
|
scenario.instantiate(&mut sim, &map);
|
||||||
(map, edits, control_map, sim)
|
(map, control_map, sim)
|
||||||
} else {
|
} else {
|
||||||
info!("Loading map {}", input);
|
info!("Loading map {}", input);
|
||||||
let map = Map::new(&input, &edits).expect("Couldn't load map");
|
let map = Map::new(&input, edits.road_edits.clone()).expect("Couldn't load map");
|
||||||
let control_map = ControlMap::new(&map);
|
let control_map = ControlMap::new(&map, &edits.stop_signs, &edits.traffic_signals);
|
||||||
flame::start("create sim");
|
flame::start("create sim");
|
||||||
let sim = Sim::new(&map, scenario_name, rng_seed, savestate_every);
|
let sim = Sim::new(&map, scenario_name, rng_seed, savestate_every);
|
||||||
flame::end("create sim");
|
flame::end("create sim");
|
||||||
(map, edits, control_map, sim)
|
(map, control_map, sim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ extern crate serde_derive;
|
|||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
mod driving;
|
mod driving;
|
||||||
|
mod edits;
|
||||||
mod events;
|
mod events;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod instrument;
|
mod instrument;
|
||||||
@ -51,6 +52,7 @@ mod walking;
|
|||||||
|
|
||||||
use abstutil::Cloneable;
|
use abstutil::Cloneable;
|
||||||
use dimensioned::si;
|
use dimensioned::si;
|
||||||
|
pub use edits::MapEdits;
|
||||||
pub use events::Event;
|
pub use events::Event;
|
||||||
use geom::{Angle, Pt2D};
|
use geom::{Angle, Pt2D};
|
||||||
pub use helpers::load;
|
pub use helpers::load;
|
||||||
|
@ -5,7 +5,7 @@ extern crate sim;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn aorta_model_completes() {
|
fn aorta_model_completes() {
|
||||||
let (map, _, control_map, mut sim) = sim::load(
|
let (map, control_map, mut sim) = sim::load(
|
||||||
"../data/maps/small.abst".to_string(),
|
"../data/maps/small.abst".to_string(),
|
||||||
"aorta_model_completes".to_string(),
|
"aorta_model_completes".to_string(),
|
||||||
Some(42),
|
Some(42),
|
||||||
|
@ -5,7 +5,7 @@ extern crate sim;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
let (map, _, _, mut sim) = sim::load(
|
let (map, _, mut sim) = sim::load(
|
||||||
"../data/maps/small.abst".to_string(),
|
"../data/maps/small.abst".to_string(),
|
||||||
"serialization".to_string(),
|
"serialization".to_string(),
|
||||||
Some(42),
|
Some(42),
|
||||||
@ -22,7 +22,7 @@ fn serialization() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn from_scratch() {
|
fn from_scratch() {
|
||||||
println!("Creating two simulations");
|
println!("Creating two simulations");
|
||||||
let (map, _, control_map, mut sim1) = sim::load(
|
let (map, control_map, mut sim1) = sim::load(
|
||||||
"../data/maps/small.abst".to_string(),
|
"../data/maps/small.abst".to_string(),
|
||||||
"from_scratch_1".to_string(),
|
"from_scratch_1".to_string(),
|
||||||
Some(42),
|
Some(42),
|
||||||
@ -49,7 +49,7 @@ fn from_scratch() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn with_savestating() {
|
fn with_savestating() {
|
||||||
println!("Creating two simulations");
|
println!("Creating two simulations");
|
||||||
let (map, _, control_map, mut sim1) = sim::load(
|
let (map, control_map, mut sim1) = sim::load(
|
||||||
"../data/maps/small.abst".to_string(),
|
"../data/maps/small.abst".to_string(),
|
||||||
"with_savestating_1".to_string(),
|
"with_savestating_1".to_string(),
|
||||||
Some(42),
|
Some(42),
|
||||||
|
@ -5,6 +5,7 @@ extern crate map_model;
|
|||||||
extern crate sim;
|
extern crate sim;
|
||||||
|
|
||||||
use map_model::LaneID;
|
use map_model::LaneID;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
// TODO refactor a few more things to make these more succinct?
|
// TODO refactor a few more things to make these more succinct?
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ fn setup(
|
|||||||
map: map_model::Map,
|
map: map_model::Map,
|
||||||
) -> (map_model::Map, control::ControlMap, sim::Sim) {
|
) -> (map_model::Map, control::ControlMap, sim::Sim) {
|
||||||
let rng_seed = 123;
|
let rng_seed = 123;
|
||||||
let control_map = control::ControlMap::new(&map);
|
let control_map = control::ControlMap::new(&map, &BTreeMap::new(), &BTreeMap::new());
|
||||||
let sim = sim::Sim::new(&map, scenario_name.to_string(), Some(rng_seed), None);
|
let sim = sim::Sim::new(&map, scenario_name.to_string(), Some(rng_seed), None);
|
||||||
(map, control_map, sim)
|
(map, control_map, sim)
|
||||||
}
|
}
|
||||||
@ -71,7 +72,6 @@ fn setup(
|
|||||||
fn make_test_map() -> map_model::Map {
|
fn make_test_map() -> map_model::Map {
|
||||||
use dimensioned::si;
|
use dimensioned::si;
|
||||||
use map_model::{raw_data, LaneType};
|
use map_model::{raw_data, LaneType};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
let left = geom::LonLat::new(100.0, 50.0);
|
let left = geom::LonLat::new(100.0, 50.0);
|
||||||
let right = geom::LonLat::new(200.0, 50.0);
|
let right = geom::LonLat::new(200.0, 50.0);
|
||||||
@ -116,7 +116,7 @@ fn make_test_map() -> map_model::Map {
|
|||||||
areas: Vec::new(),
|
areas: Vec::new(),
|
||||||
coordinates_in_world_space: true,
|
coordinates_in_world_space: true,
|
||||||
},
|
},
|
||||||
&map_model::Edits::new(),
|
map_model::RoadEdits::new(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(map.all_roads().len(), 1);
|
assert_eq!(map.all_roads().len(), 1);
|
||||||
|
@ -5,7 +5,7 @@ extern crate sim;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bus_reaches_stops() {
|
fn bus_reaches_stops() {
|
||||||
let (map, _, control_map, mut sim) = sim::load(
|
let (map, control_map, mut sim) = sim::load(
|
||||||
"../data/maps/small.abst".to_string(),
|
"../data/maps/small.abst".to_string(),
|
||||||
"bus_reaches_stops".to_string(),
|
"bus_reaches_stops".to_string(),
|
||||||
Some(42),
|
Some(42),
|
||||||
@ -33,7 +33,7 @@ fn bus_reaches_stops() {
|
|||||||
// TODO this test is strictly more complicated than bus_reaches_stops, should it subsume it?
|
// TODO this test is strictly more complicated than bus_reaches_stops, should it subsume it?
|
||||||
#[test]
|
#[test]
|
||||||
fn ped_uses_bus() {
|
fn ped_uses_bus() {
|
||||||
let (map, _, control_map, mut sim) = sim::load(
|
let (map, control_map, mut sim) = sim::load(
|
||||||
"../data/maps/small.abst".to_string(),
|
"../data/maps/small.abst".to_string(),
|
||||||
"bus_reaches_stops".to_string(),
|
"bus_reaches_stops".to_string(),
|
||||||
Some(42),
|
Some(42),
|
||||||
|
Loading…
Reference in New Issue
Block a user