mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
A humble start to deleting lanes. #597
This commit is contained in:
parent
c6906f6153
commit
584c1be9e0
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
@ -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)
|
||||||
|
@ -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(),
|
||||||
|
Loading…
Reference in New Issue
Block a user