mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 03:35:51 +03:00
Introduce a consolidated EditCmd::ChangeRoad. Unused so far, and not
handling backwards compatibility yet. One step towards fixing #113 and
This commit is contained in:
parent
1c27ba39c7
commit
aacb17297d
@ -480,17 +480,24 @@ impl State for LoadEdits {
|
||||
}
|
||||
// TODO Hack. Have to replace ourselves, because the Menu might be
|
||||
// invalidated now that something was chosen.
|
||||
Err(err) => Transition::Multi(vec![
|
||||
Transition::Replace(LoadEdits::new(ctx, app, self.mode.clone())),
|
||||
// TODO Menu draws at a weird Z-order to deal with tooltips, so now
|
||||
// the menu underneath bleeds
|
||||
// through
|
||||
Transition::Push(PopupMsg::new(
|
||||
ctx,
|
||||
"Error",
|
||||
vec![format!("Can't load {}", path), err.clone()],
|
||||
)),
|
||||
]),
|
||||
Err(err) => {
|
||||
println!("Can't load {}: {}", path, err);
|
||||
Transition::Multi(vec![
|
||||
Transition::Replace(LoadEdits::new(
|
||||
ctx,
|
||||
app,
|
||||
self.mode.clone(),
|
||||
)),
|
||||
// TODO Menu draws at a weird Z-order to deal with tooltips, so
|
||||
// now the menu underneath
|
||||
// bleeds through
|
||||
Transition::Push(PopupMsg::new(
|
||||
ctx,
|
||||
"Error",
|
||||
vec![format!("Can't load {}", path), err.clone()],
|
||||
)),
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -747,6 +754,7 @@ fn cmd_to_id(cmd: &EditCmd) -> Option<ID> {
|
||||
EditCmd::ChangeLaneType { id, .. } => Some(ID::Lane(*id)),
|
||||
EditCmd::ReverseLane { l, .. } => Some(ID::Lane(*l)),
|
||||
EditCmd::ChangeSpeedLimit { id, .. } => Some(ID::Road(*id)),
|
||||
EditCmd::ChangeRoad { r, .. } => Some(ID::Road(*r)),
|
||||
EditCmd::ChangeIntersection { i, .. } => Some(ID::Intersection(*i)),
|
||||
EditCmd::ChangeAccessRestrictions { id, .. } => Some(ID::Road(*id)),
|
||||
EditCmd::ChangeRouteSchedule { .. } => None,
|
||||
|
@ -172,6 +172,11 @@ impl GameplayMode {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeRoad { .. } => {
|
||||
if !self.can_edit_lanes() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeIntersection { ref new, .. } => match new {
|
||||
// TODO Conflating construction
|
||||
EditIntersection::StopSign(_) | EditIntersection::Closed => {
|
||||
|
@ -1,14 +1,16 @@
|
||||
mod compat;
|
||||
mod perma;
|
||||
|
||||
use crate::make::initial::lane_specs::get_lane_specs_ltr;
|
||||
use crate::{
|
||||
connectivity, AccessRestrictions, BusRouteID, ControlStopSign, ControlTrafficSignal, Direction,
|
||||
IntersectionID, IntersectionType, LaneID, LaneType, Map, PathConstraints, Pathfinder, RoadID,
|
||||
TurnID, Zone,
|
||||
IntersectionID, IntersectionType, LaneID, LaneType, Map, PathConstraints, Pathfinder, Road,
|
||||
RoadID, TurnID, Zone,
|
||||
};
|
||||
use abstutil::{retain_btreemap, retain_btreeset, Timer};
|
||||
use geom::{Speed, Time};
|
||||
pub use perma::{OriginalLane, PermanentMapEdits};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@ -19,6 +21,8 @@ pub struct MapEdits {
|
||||
// Derived from commands, kept up to date by update_derived
|
||||
pub original_lts: BTreeMap<LaneID, LaneType>,
|
||||
pub reversed_lanes: BTreeSet<LaneID>,
|
||||
// TODO Do we need to store the original? We can just do EditRoad::get_orig_from_osm.
|
||||
pub original_roads: BTreeMap<RoadID, EditRoad>,
|
||||
pub original_intersections: BTreeMap<IntersectionID, EditIntersection>,
|
||||
pub changed_speed_limits: BTreeSet<RoadID>,
|
||||
pub changed_access_restrictions: BTreeSet<RoadID>,
|
||||
@ -39,18 +43,46 @@ pub enum EditIntersection {
|
||||
Closed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EditRoad {
|
||||
lanes_ltr: Vec<(LaneType, Direction)>,
|
||||
speed_limit: Speed,
|
||||
access_restrictions: AccessRestrictions,
|
||||
}
|
||||
|
||||
impl EditRoad {
|
||||
fn get_orig_from_osm(r: &Road) -> EditRoad {
|
||||
EditRoad {
|
||||
lanes_ltr: get_lane_specs_ltr(&r.osm_tags)
|
||||
.into_iter()
|
||||
.map(|spec| (spec.lt, spec.dir))
|
||||
.collect(),
|
||||
speed_limit: r.speed_limit_from_osm(),
|
||||
access_restrictions: r.access_restrictions_from_osm(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum EditCmd {
|
||||
ChangeRoad {
|
||||
r: RoadID,
|
||||
old: EditRoad,
|
||||
new: EditRoad,
|
||||
},
|
||||
// TODO Deprecated
|
||||
ChangeLaneType {
|
||||
id: LaneID,
|
||||
lt: LaneType,
|
||||
orig_lt: LaneType,
|
||||
},
|
||||
// TODO Deprecated
|
||||
ReverseLane {
|
||||
l: LaneID,
|
||||
// New intended dst_i
|
||||
dst_i: IntersectionID,
|
||||
},
|
||||
// TODO Deprecated
|
||||
ChangeSpeedLimit {
|
||||
id: RoadID,
|
||||
new: Speed,
|
||||
@ -61,6 +93,7 @@ pub enum EditCmd {
|
||||
new: EditIntersection,
|
||||
old: EditIntersection,
|
||||
},
|
||||
// TODO Deprecated
|
||||
ChangeAccessRestrictions {
|
||||
id: RoadID,
|
||||
new: AccessRestrictions,
|
||||
@ -91,6 +124,7 @@ impl MapEdits {
|
||||
|
||||
original_lts: BTreeMap::new(),
|
||||
reversed_lanes: BTreeSet::new(),
|
||||
original_roads: BTreeMap::new(),
|
||||
original_intersections: BTreeMap::new(),
|
||||
changed_speed_limits: BTreeSet::new(),
|
||||
changed_access_restrictions: BTreeSet::new(),
|
||||
@ -122,66 +156,70 @@ impl MapEdits {
|
||||
}
|
||||
|
||||
fn update_derived(&mut self, map: &Map) {
|
||||
let mut orig_lts = BTreeMap::new();
|
||||
let mut reversed_lanes = BTreeSet::new();
|
||||
let mut orig_intersections: BTreeMap<IntersectionID, EditIntersection> = BTreeMap::new();
|
||||
let mut changed_speed_limits = BTreeSet::new();
|
||||
let mut changed_access_restrictions = BTreeSet::new();
|
||||
let mut changed_routes = BTreeSet::new();
|
||||
self.original_lts.clear();
|
||||
self.reversed_lanes.clear();
|
||||
self.original_roads.clear();
|
||||
self.original_intersections.clear();
|
||||
self.changed_speed_limits.clear();
|
||||
self.changed_access_restrictions.clear();
|
||||
self.changed_routes.clear();
|
||||
|
||||
for cmd in &self.commands {
|
||||
match cmd {
|
||||
EditCmd::ChangeLaneType { id, orig_lt, .. } => {
|
||||
if !orig_lts.contains_key(id) {
|
||||
orig_lts.insert(*id, *orig_lt);
|
||||
if !self.original_lts.contains_key(id) {
|
||||
self.original_lts.insert(*id, *orig_lt);
|
||||
}
|
||||
}
|
||||
EditCmd::ReverseLane { l, .. } => {
|
||||
if reversed_lanes.contains(l) {
|
||||
reversed_lanes.remove(l);
|
||||
if self.reversed_lanes.contains(l) {
|
||||
self.reversed_lanes.remove(l);
|
||||
} else {
|
||||
reversed_lanes.insert(*l);
|
||||
self.reversed_lanes.insert(*l);
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeSpeedLimit { id, .. } => {
|
||||
changed_speed_limits.insert(*id);
|
||||
self.changed_speed_limits.insert(*id);
|
||||
}
|
||||
EditCmd::ChangeRoad { r, ref old, .. } => {
|
||||
if !self.original_roads.contains_key(r) {
|
||||
self.original_roads.insert(*r, old.clone());
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeIntersection { i, ref old, .. } => {
|
||||
if !orig_intersections.contains_key(i) {
|
||||
orig_intersections.insert(*i, old.clone());
|
||||
if !self.original_intersections.contains_key(i) {
|
||||
self.original_intersections.insert(*i, old.clone());
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeAccessRestrictions { id, .. } => {
|
||||
changed_access_restrictions.insert(*id);
|
||||
self.changed_access_restrictions.insert(*id);
|
||||
}
|
||||
EditCmd::ChangeRouteSchedule { id, .. } => {
|
||||
changed_routes.insert(*id);
|
||||
self.changed_routes.insert(*id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retain_btreemap(&mut orig_lts, |l, lt| map.get_l(*l).lane_type != *lt);
|
||||
retain_btreemap(&mut orig_intersections, |i, orig| {
|
||||
retain_btreemap(&mut self.original_lts, |l, lt| {
|
||||
map.get_l(*l).lane_type != *lt
|
||||
});
|
||||
retain_btreemap(&mut self.original_roads, |r, orig| {
|
||||
map.get_r_edit(*r) != orig.clone()
|
||||
});
|
||||
retain_btreemap(&mut self.original_intersections, |i, orig| {
|
||||
map.get_i_edit(*i) != orig.clone()
|
||||
});
|
||||
retain_btreeset(&mut changed_speed_limits, |r| {
|
||||
retain_btreeset(&mut self.changed_speed_limits, |r| {
|
||||
map.get_r(*r).speed_limit != map.get_r(*r).speed_limit_from_osm()
|
||||
});
|
||||
retain_btreeset(&mut changed_access_restrictions, |r| {
|
||||
retain_btreeset(&mut self.changed_access_restrictions, |r| {
|
||||
let r = map.get_r(*r);
|
||||
r.access_restrictions_from_osm() != r.access_restrictions
|
||||
});
|
||||
retain_btreeset(&mut changed_routes, |br| {
|
||||
retain_btreeset(&mut self.changed_routes, |br| {
|
||||
let r = map.get_br(*br);
|
||||
r.spawn_times != r.orig_spawn_times
|
||||
});
|
||||
|
||||
self.original_lts = orig_lts;
|
||||
self.reversed_lanes = reversed_lanes;
|
||||
self.original_intersections = orig_intersections;
|
||||
self.changed_speed_limits = changed_speed_limits;
|
||||
self.changed_access_restrictions = changed_access_restrictions;
|
||||
self.changed_routes = changed_routes;
|
||||
}
|
||||
|
||||
// Assumes update_derived has been called.
|
||||
@ -199,6 +237,13 @@ impl MapEdits {
|
||||
orig_lt: *orig_lt,
|
||||
});
|
||||
}
|
||||
for (r, old) in &self.original_roads {
|
||||
self.commands.push(EditCmd::ChangeRoad {
|
||||
r: *r,
|
||||
old: old.clone(),
|
||||
new: map.get_r_edit(*r),
|
||||
});
|
||||
}
|
||||
for (i, old) in &self.original_intersections {
|
||||
self.commands.push(EditCmd::ChangeIntersection {
|
||||
i: *i,
|
||||
@ -254,6 +299,8 @@ impl EditCmd {
|
||||
EditCmd::ChangeLaneType { lt, id, .. } => format!("{} on #{}", lt.short_name(), id.0),
|
||||
EditCmd::ReverseLane { l, .. } => format!("reverse {}", l),
|
||||
EditCmd::ChangeSpeedLimit { id, new, .. } => format!("limit {} for {}", new, id),
|
||||
// TODO Way more details
|
||||
EditCmd::ChangeRoad { r, .. } => format!("road #{}", r.0),
|
||||
EditCmd::ChangeIntersection { i, new, .. } => match new {
|
||||
EditIntersection::StopSign(_) => format!("stop sign #{}", i.0),
|
||||
EditIntersection::TrafficSignal(_) => format!("traffic signal #{}", i.0),
|
||||
@ -343,6 +390,49 @@ impl EditCmd {
|
||||
false
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeRoad { r, ref new, .. } => {
|
||||
if map.get_r_edit(*r) == new.clone() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let road = &mut map.roads[r.0];
|
||||
road.speed_limit = new.speed_limit;
|
||||
road.access_restrictions = new.access_restrictions.clone();
|
||||
assert_eq!(road.lanes_ltr.len(), new.lanes_ltr.len());
|
||||
for (idx, (lt, dir)) in new.lanes_ltr.clone().into_iter().enumerate() {
|
||||
let lane = &mut map.lanes[(road.lanes_ltr[idx].0).0];
|
||||
road.lanes_ltr[idx].2 = lt;
|
||||
lane.lane_type = lt;
|
||||
|
||||
// Direction change?
|
||||
if road.lanes_ltr[idx].1 != dir {
|
||||
road.lanes_ltr[idx].1 = dir;
|
||||
std::mem::swap(&mut lane.src_i, &mut lane.dst_i);
|
||||
lane.lane_center_pts = lane.lane_center_pts.reversed();
|
||||
}
|
||||
}
|
||||
|
||||
effects.changed_roads.insert(road.id);
|
||||
for i in vec![road.src_i, road.dst_i] {
|
||||
effects.changed_intersections.insert(i);
|
||||
let i = &mut map.intersections[i.0];
|
||||
i.outgoing_lanes.clear();
|
||||
i.incoming_lanes.clear();
|
||||
for r in &i.roads {
|
||||
for (l, _, _) in map.roads[r.0].lanes_ltr() {
|
||||
if map.lanes[l.0].src_i == i.id {
|
||||
i.outgoing_lanes.push(l);
|
||||
} else {
|
||||
assert_eq!(map.lanes[l.0].dst_i, i.id);
|
||||
i.incoming_lanes.push(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recalculate_turns(i.id, map, effects, timer);
|
||||
}
|
||||
true
|
||||
}
|
||||
EditCmd::ChangeIntersection {
|
||||
i,
|
||||
ref new,
|
||||
@ -429,6 +519,16 @@ impl EditCmd {
|
||||
false
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeRoad {
|
||||
r,
|
||||
ref old,
|
||||
ref new,
|
||||
} => EditCmd::ChangeRoad {
|
||||
r: *r,
|
||||
old: new.clone(),
|
||||
new: old.clone(),
|
||||
}
|
||||
.apply(effects, map, timer),
|
||||
EditCmd::ChangeIntersection {
|
||||
i,
|
||||
ref old,
|
||||
@ -516,6 +616,19 @@ impl Map {
|
||||
&self.edits
|
||||
}
|
||||
|
||||
pub fn get_r_edit(&self, r: RoadID) -> EditRoad {
|
||||
let r = self.get_r(r);
|
||||
EditRoad {
|
||||
lanes_ltr: r
|
||||
.lanes_ltr()
|
||||
.into_iter()
|
||||
.map(|(_, dir, lt)| (lt, dir))
|
||||
.collect(),
|
||||
speed_limit: r.speed_limit,
|
||||
access_restrictions: r.access_restrictions.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
// Panics on borders
|
||||
pub fn get_i_edit(&self, i: IntersectionID) -> EditIntersection {
|
||||
match self.get_i(i).intersection_type {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::edits::{EditCmd, EditIntersection, MapEdits};
|
||||
use crate::edits::{EditCmd, EditIntersection, EditRoad, MapEdits};
|
||||
use crate::raw::OriginalRoad;
|
||||
use crate::{
|
||||
osm, AccessRestrictions, ControlStopSign, Direction, IntersectionID, LaneID, LaneType, Map,
|
||||
@ -36,6 +36,7 @@ enum PermanentEditIntersection {
|
||||
Closed,
|
||||
}
|
||||
|
||||
// TODO Deprecated
|
||||
// Enough data to notice when lanes along a road have changed
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct OriginalLane {
|
||||
@ -63,6 +64,11 @@ enum PermanentEditCmd {
|
||||
new: Speed,
|
||||
old: Speed,
|
||||
},
|
||||
ChangeRoad {
|
||||
r: OriginalRoad,
|
||||
new: EditRoad,
|
||||
old: EditRoad,
|
||||
},
|
||||
ChangeIntersection {
|
||||
i: osm::NodeID,
|
||||
new: PermanentEditIntersection,
|
||||
@ -111,6 +117,11 @@ impl PermanentMapEdits {
|
||||
old: *old,
|
||||
}
|
||||
}
|
||||
EditCmd::ChangeRoad { r, new, old } => PermanentEditCmd::ChangeRoad {
|
||||
r: map.get_r(*r).orig_id,
|
||||
new: new.clone(),
|
||||
old: old.clone(),
|
||||
},
|
||||
EditCmd::ChangeIntersection { i, new, old } => {
|
||||
PermanentEditCmd::ChangeIntersection {
|
||||
i: map.get_i(*i).orig_id,
|
||||
@ -168,6 +179,19 @@ impl PermanentMapEdits {
|
||||
let id = map.find_r_by_osm_id(id)?;
|
||||
Ok(EditCmd::ChangeSpeedLimit { id, new, old })
|
||||
}
|
||||
PermanentEditCmd::ChangeRoad { r, new, old } => {
|
||||
let id = map.find_r_by_osm_id(r)?;
|
||||
let num_current = map.get_r(id).lanes_ltr().len();
|
||||
if num_current != new.lanes_ltr.len() {
|
||||
return Err(format!(
|
||||
"number of lanes in {} is {} now, but {} in the edits",
|
||||
r,
|
||||
num_current,
|
||||
new.lanes_ltr.len()
|
||||
));
|
||||
}
|
||||
Ok(EditCmd::ChangeRoad { r: id, new, old })
|
||||
}
|
||||
PermanentEditCmd::ChangeIntersection { i, new, old } => {
|
||||
let id = map.find_i_by_osm_id(i)?;
|
||||
Ok(EditCmd::ChangeIntersection {
|
||||
@ -199,6 +223,7 @@ impl PermanentMapEdits {
|
||||
|
||||
original_lts: BTreeMap::new(),
|
||||
reversed_lanes: BTreeSet::new(),
|
||||
original_roads: BTreeMap::new(),
|
||||
original_intersections: BTreeMap::new(),
|
||||
changed_speed_limits: BTreeSet::new(),
|
||||
changed_access_restrictions: BTreeSet::new(),
|
||||
|
@ -41,6 +41,8 @@ pub struct Intersection {
|
||||
|
||||
// Note that a lane may belong to both incoming_lanes and outgoing_lanes.
|
||||
// TODO narrow down when and why. is it just sidewalks in weird cases?
|
||||
// TODO Change to BTreeSet, or otherwise emphasize to callers that the order of these isn't
|
||||
// meaningful
|
||||
pub incoming_lanes: Vec<LaneID>,
|
||||
pub outgoing_lanes: Vec<LaneID>,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user