A humble start to deleting lanes. #597

This commit is contained in:
Dustin Carlino 2021-04-08 15:46:56 -07:00
parent c6906f6153
commit 584c1be9e0
7 changed files with 103 additions and 24 deletions

View File

@ -1,5 +1,3 @@
use std::collections::BTreeSet;
use maplit::btreeset; use maplit::btreeset;
use abstutil::{prettyprint_usize, Timer}; use abstutil::{prettyprint_usize, Timer};
@ -676,7 +674,7 @@ fn make_topcenter(ctx: &mut EventCtx, app: &App) -> Panel {
pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) { pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {
let mut timer = Timer::new("apply map edits"); let mut timer = Timer::new("apply map edits");
let (roads_changed, turns_deleted, turns_added, mut modified_intersections) = let (roads_changed, lanes_deleted, turns_deleted, turns_added, mut modified_intersections) =
app.primary.map.must_apply_edits(edits); app.primary.map.must_apply_edits(edits);
if !roads_changed.is_empty() || !modified_intersections.is_empty() { if !roads_changed.is_empty() || !modified_intersections.is_empty() {
@ -702,13 +700,14 @@ pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {
} }
} }
let mut lanes_of_modified_turns: BTreeSet<LaneID> = BTreeSet::new(); for l in lanes_deleted {
app.primary.draw_map.delete_lane(l);
}
for t in turns_deleted { for t in turns_deleted {
lanes_of_modified_turns.insert(t.src);
modified_intersections.insert(t.parent); modified_intersections.insert(t.parent);
} }
for t in &turns_added { for t in &turns_added {
lanes_of_modified_turns.insert(t.src);
modified_intersections.insert(t.parent); modified_intersections.insert(t.parent);
} }

View File

@ -14,6 +14,9 @@ pub fn prompt_for_lanes(ctx: &mut EventCtx, road: &Road) -> Box<dyn State<App>>
"Define lanes_ltr", "Define lanes_ltr",
lanes_to_string(road), lanes_to_string(road),
Box::new(move |string, ctx, app| { Box::new(move |string, ctx, app| {
// We're selecting a lane before this, but the ID is probably about to be invalidated.
app.primary.current_selection = None;
let mut edits = app.primary.map.get_edits().clone(); let mut edits = app.primary.map.get_edits().clone();
edits.commands.push(app.primary.map.edit_road_cmd(r, |new| { edits.commands.push(app.primary.map.edit_road_cmd(r, |new| {
new.lanes_ltr = string_to_lanes(string.clone()); new.lanes_ltr = string_to_lanes(string.clone());

View File

@ -39,6 +39,8 @@ pub struct DrawMap {
pub show_zorder: isize, pub show_zorder: isize,
quadtree: QuadTree<ID>, quadtree: QuadTree<ID>,
// Remember these so we can delete lanes.
lane_ids: HashMap<LaneID, aabb_quadtree::ItemId>,
} }
impl DrawMap { impl DrawMap {
@ -140,12 +142,15 @@ impl DrawMap {
timer.start("create quadtree"); timer.start("create quadtree");
let mut quadtree = QuadTree::default(map.get_bounds().as_bbox()); let mut quadtree = QuadTree::default(map.get_bounds().as_bbox());
let mut lane_ids = HashMap::new();
// TODO use iter chain if everything was boxed as a renderable... // TODO use iter chain if everything was boxed as a renderable...
for obj in &roads { for obj in &roads {
quadtree.insert_with_box(obj.get_id(), obj.get_outline(map).get_bounds().as_bbox()); quadtree.insert_with_box(obj.get_id(), obj.get_outline(map).get_bounds().as_bbox());
} }
for (_, obj) in &lanes { for (_, obj) in &lanes {
let item_id =
quadtree.insert_with_box(obj.get_id(), obj.get_outline(map).get_bounds().as_bbox()); quadtree.insert_with_box(obj.get_id(), obj.get_outline(map).get_bounds().as_bbox());
lane_ids.insert(obj.id, item_id);
} }
for obj in &intersections { for obj in &intersections {
quadtree.insert_with_box(obj.get_id(), obj.get_outline(map).get_bounds().as_bbox()); quadtree.insert_with_box(obj.get_id(), obj.get_outline(map).get_bounds().as_bbox());
@ -187,6 +192,7 @@ impl DrawMap {
draw_all_areas, draw_all_areas,
quadtree, quadtree,
lane_ids,
zorder_range: (low_z, high_z), zorder_range: (low_z, high_z),
show_zorder: high_z, show_zorder: high_z,
@ -439,4 +445,10 @@ impl DrawMap {
batch batch
} }
pub fn delete_lane(&mut self, l: LaneID) {
self.lanes.remove(&l).unwrap();
let item_id = self.lane_ids.remove(&l).unwrap();
self.quadtree.remove(item_id).unwrap();
}
} }

View File

@ -127,6 +127,7 @@ pub enum EditCmd {
pub struct EditEffects { pub struct EditEffects {
pub changed_roads: BTreeSet<RoadID>, pub changed_roads: BTreeSet<RoadID>,
pub deleted_lanes: BTreeSet<LaneID>,
pub changed_intersections: BTreeSet<IntersectionID>, pub changed_intersections: BTreeSet<IntersectionID>,
pub added_turns: BTreeSet<TurnID>, pub added_turns: BTreeSet<TurnID>,
pub deleted_turns: BTreeSet<TurnID>, pub deleted_turns: BTreeSet<TurnID>,
@ -233,6 +234,7 @@ impl MapEdits {
} }
/// Pick apart changed_roads and figure out if an entire road was edited, or just a few lanes. /// Pick apart changed_roads and figure out if an entire road was edited, or just a few lanes.
/// Doesn't return deleted lanes.
pub fn changed_lanes(&self, map: &Map) -> (BTreeSet<LaneID>, BTreeSet<RoadID>) { pub fn changed_lanes(&self, map: &Map) -> (BTreeSet<LaneID>, BTreeSet<RoadID>) {
let mut lanes = BTreeSet::new(); let mut lanes = BTreeSet::new();
let mut roads = BTreeSet::new(); let mut roads = BTreeSet::new();
@ -246,6 +248,11 @@ impl MapEdits {
roads.insert(r.id); roads.insert(r.id);
} else { } else {
let lanes_ltr = r.lanes_ltr(); let lanes_ltr = r.lanes_ltr();
if lanes_ltr.len() != orig.lanes_ltr.len() {
// If a lane was added or deleted, figuring out if any were modified is kind of
// unclear -- just mark the entire road.
roads.insert(r.id);
} else {
for (idx, (lt, dir)) in orig.lanes_ltr.into_iter().enumerate() { for (idx, (lt, dir)) in orig.lanes_ltr.into_iter().enumerate() {
if lanes_ltr[idx].1 != dir || lanes_ltr[idx].2 != lt { if lanes_ltr[idx].1 != dir || lanes_ltr[idx].2 != lt {
lanes.insert(lanes_ltr[idx].0); lanes.insert(lanes_ltr[idx].0);
@ -253,6 +260,7 @@ impl MapEdits {
} }
} }
} }
}
(lanes, roads) (lanes, roads)
} }
} }
@ -267,6 +275,7 @@ impl EditEffects {
pub fn new() -> EditEffects { pub fn new() -> EditEffects {
EditEffects { EditEffects {
changed_roads: BTreeSet::new(), changed_roads: BTreeSet::new(),
deleted_lanes: BTreeSet::new(),
changed_intersections: BTreeSet::new(), changed_intersections: BTreeSet::new(),
added_turns: BTreeSet::new(), added_turns: BTreeSet::new(),
deleted_turns: BTreeSet::new(), deleted_turns: BTreeSet::new(),
@ -307,7 +316,7 @@ impl EditCmd {
let road = &mut map.roads[r.0]; let road = &mut map.roads[r.0];
road.speed_limit = new.speed_limit; road.speed_limit = new.speed_limit;
road.access_restrictions = new.access_restrictions.clone(); road.access_restrictions = new.access_restrictions.clone();
assert_eq!(road.lanes_ltr.len(), new.lanes_ltr.len()); if road.lanes_ltr.len() == new.lanes_ltr.len() {
for (idx, (lt, dir)) in new.lanes_ltr.clone().into_iter().enumerate() { for (idx, (lt, dir)) in new.lanes_ltr.clone().into_iter().enumerate() {
let lane = map.lanes.get_mut(&road.lanes_ltr[idx].0).unwrap(); let lane = map.lanes.get_mut(&road.lanes_ltr[idx].0).unwrap();
road.lanes_ltr[idx].2 = lt; road.lanes_ltr[idx].2 = lt;
@ -321,6 +330,11 @@ impl EditCmd {
lane.dir = dir; lane.dir = dir;
} }
} }
} else {
modify_road_width(map, *r, new.lanes_ltr.clone(), effects);
}
// Re-borrow
let road = &mut map.roads[r.0];
effects.changed_roads.insert(road.id); effects.changed_roads.insert(road.id);
for i in vec![road.src_i, road.dst_i] { for i in vec![road.src_i, road.dst_i] {
@ -454,6 +468,49 @@ fn recalculate_turns(id: IntersectionID, map: &mut Map, effects: &mut EditEffect
} }
} }
fn modify_road_width(
map: &mut Map,
r: RoadID,
lanes_ltr: Vec<(LaneType, Direction)>,
effects: &mut EditEffects,
) {
let before = map.roads[r.0].lanes_ltr.len();
let after = lanes_ltr.len();
if after < before {
// Same as the normal case...
let road = &mut map.roads[r.0];
for (idx, (lt, dir)) in lanes_ltr.into_iter().enumerate() {
let lane = map.lanes.get_mut(&road.lanes_ltr[idx].0).unwrap();
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();
lane.dir = dir;
}
}
// Delete some stuff!
for _ in 0..before - after {
let (l, _, _) = road.lanes_ltr.pop().unwrap();
map.lanes.remove(&l).unwrap();
effects.deleted_lanes.insert(l);
}
} else {
// TODO Adding lanes
}
// TODO We need to recalculate the road center line, all of the lane geometry, the intersection
// geometry...
// TODO We need to update buildings, bus stops, and parking lots -- they may refer to an old
// ID.
}
impl Map { impl Map {
pub fn new_edits(&self) -> MapEdits { pub fn new_edits(&self) -> MapEdits {
let mut edits = MapEdits::new(); let mut edits = MapEdits::new();
@ -519,11 +576,13 @@ impl Map {
edits.save(self); edits.save(self);
} }
/// Returns (roads_changed, lanes_deleted, turns_deleted, turns_added, modified_intersections)
pub fn must_apply_edits( pub fn must_apply_edits(
&mut self, &mut self,
new_edits: MapEdits, new_edits: MapEdits,
) -> ( ) -> (
BTreeSet<RoadID>, BTreeSet<RoadID>,
BTreeSet<LaneID>,
BTreeSet<TurnID>, BTreeSet<TurnID>,
BTreeSet<TurnID>, BTreeSet<TurnID>,
BTreeSet<IntersectionID>, BTreeSet<IntersectionID>,
@ -536,14 +595,14 @@ impl Map {
} }
// new_edits don't necessarily have to be valid; this could be used for speculatively testing // new_edits don't necessarily have to be valid; this could be used for speculatively testing
// edits. Returns roads changed, turns deleted, turns added, intersections modified. Doesn't // edits. Doesn't update pathfinding yet.
// update pathfinding yet.
fn apply_edits( fn apply_edits(
&mut self, &mut self,
mut new_edits: MapEdits, mut new_edits: MapEdits,
enforce_valid: bool, enforce_valid: bool,
) -> ( ) -> (
BTreeSet<RoadID>, BTreeSet<RoadID>,
BTreeSet<LaneID>,
BTreeSet<TurnID>, BTreeSet<TurnID>,
BTreeSet<TurnID>, BTreeSet<TurnID>,
BTreeSet<IntersectionID>, BTreeSet<IntersectionID>,
@ -555,6 +614,7 @@ impl Map {
BTreeSet::new(), BTreeSet::new(),
BTreeSet::new(), BTreeSet::new(),
BTreeSet::new(), BTreeSet::new(),
BTreeSet::new(),
); );
} }
@ -622,6 +682,7 @@ impl Map {
( (
effects.changed_roads, effects.changed_roads,
effects.deleted_lanes,
effects.deleted_turns, effects.deleted_turns,
// Some of these might've been added, then later deleted. // Some of these might've been added, then later deleted.
effects effects

View File

@ -84,6 +84,7 @@ pub(crate) const SHOULDER_THICKNESS: Distance = Distance::const_meters(0.5);
pub struct Map { pub struct Map {
roads: Vec<Road>, roads: Vec<Road>,
lanes: BTreeMap<LaneID, Lane>, lanes: BTreeMap<LaneID, Lane>,
lane_id_counter: usize,
intersections: Vec<Intersection>, intersections: Vec<Intersection>,
#[serde( #[serde(
serialize_with = "serialize_btreemap", serialize_with = "serialize_btreemap",

View File

@ -50,6 +50,7 @@ impl Map {
let mut map = Map { let mut map = Map {
roads: Vec::new(), roads: Vec::new(),
lanes: BTreeMap::new(), lanes: BTreeMap::new(),
lane_id_counter: 0,
intersections: Vec::new(), intersections: Vec::new(),
turns: BTreeMap::new(), turns: BTreeMap::new(),
buildings: Vec::new(), buildings: Vec::new(),
@ -173,7 +174,8 @@ impl Map {
let mut width_so_far = Distance::ZERO; let mut width_so_far = Distance::ZERO;
for lane in &r.lane_specs_ltr { for lane in &r.lane_specs_ltr {
let id = LaneID(map.lanes.len()); let id = LaneID(map.lane_id_counter);
map.lane_id_counter += 1;
let (src_i, dst_i) = if lane.dir == Direction::Fwd { let (src_i, dst_i) = if lane.dir == Direction::Fwd {
(i1, i2) (i1, i2)

View File

@ -145,6 +145,7 @@ impl Map {
Map { Map {
roads: Vec::new(), roads: Vec::new(),
lanes: BTreeMap::new(), lanes: BTreeMap::new(),
lane_id_counter: 0,
intersections: Vec::new(), intersections: Vec::new(),
turns: BTreeMap::new(), turns: BTreeMap::new(),
buildings: Vec::new(), buildings: Vec::new(),