Fix lane geometry after changing the number of lanes. #597

This commit is contained in:
Dustin Carlino 2021-04-09 09:20:48 -07:00
parent 584c1be9e0
commit 14609ab157
6 changed files with 121 additions and 75 deletions

View File

@ -684,6 +684,10 @@ pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {
DrawMap::regenerate_unzoomed_layer(&app.primary.map, &app.cs, ctx, &mut timer);
}
for l in lanes_deleted {
app.primary.draw_map.delete_lane(l);
}
for r in roads_changed {
let road = app.primary.map.get_r(r);
app.primary.draw_map.roads[r.0].clear_rendering();
@ -691,19 +695,10 @@ pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {
// An edit to one lane potentially affects markings in all lanes in the same road, because
// of one-way markings, driving lines, etc.
for l in road.all_lanes() {
app.primary
.draw_map
.lanes
.get_mut(&l)
.unwrap()
.clear_rendering();
app.primary.draw_map.create_lane(l, &app.primary.map);
}
}
for l in lanes_deleted {
app.primary.draw_map.delete_lane(l);
}
for t in turns_deleted {
modified_intersections.insert(t.parent);
}

View File

@ -446,6 +446,15 @@ impl DrawMap {
batch
}
pub fn create_lane(&mut self, l: LaneID, map: &Map) {
let draw = DrawLane::new(map.get_l(l), map);
let item_id = self
.quadtree
.insert_with_box(draw.get_id(), draw.get_outline(map).get_bounds().as_bbox());
self.lane_ids.insert(l, item_id);
self.lanes.insert(l, draw);
}
pub fn delete_lane(&mut self, l: LaneID) {
self.lanes.remove(&l).unwrap();
let item_id = self.lane_ids.remove(&l).unwrap();

View File

@ -12,6 +12,7 @@ use geom::{Speed, Time};
pub use self::perma::PermanentMapEdits;
use crate::make::initial::lane_specs::get_lane_specs_ltr;
use crate::make::initial::LaneSpec;
use crate::{
connectivity, AccessRestrictions, BusRouteID, ControlStopSign, ControlTrafficSignal, Direction,
IntersectionID, IntersectionType, LaneID, LaneType, Map, MapConfig, PathConstraints,
@ -477,6 +478,12 @@ fn modify_road_width(
let before = map.roads[r.0].lanes_ltr.len();
let after = lanes_ltr.len();
// Tell the UI to delete all of the old lanes, then recreate whatever ones survived or were
// created. Even lanes not directly modified will have their geometry shift.
for (l, _, _) in map.roads[r.0].lanes_ltr() {
effects.deleted_lanes.insert(l);
}
if after < before {
// Same as the normal case...
let road = &mut map.roads[r.0];
@ -504,8 +511,31 @@ fn modify_road_width(
// TODO Adding lanes
}
// TODO We need to recalculate the road center line, all of the lane geometry, the intersection
// geometry...
// road.center_pts doesn't need to change; we'll keep the true physical center of the road and
// build around it.
// Recalculate lane geometry.
let mut lane_specs_ltr = Vec::new();
let mut lane_ids = Vec::new();
for (id, dir, lt) in map.get_r(r).lanes_ltr() {
lane_specs_ltr.push(LaneSpec {
lt,
dir,
width: map.get_l(id).width,
});
lane_ids.push(id);
}
let mut id_counter = 0;
for (new_lane, id) in map
.get_r(r)
.create_lanes(lane_specs_ltr, &mut id_counter)
.into_iter()
.zip(lane_ids)
{
map.lanes.get_mut(&id).unwrap().lane_center_pts = new_lane.lane_center_pts;
}
// TODO Recalculate intersection geometry.
// TODO We need to update buildings, bus stops, and parking lots -- they may refer to an old
// ID.
@ -576,7 +606,7 @@ impl Map {
edits.save(self);
}
/// Returns (roads_changed, lanes_deleted, turns_deleted, turns_added, modified_intersections)
/// Returns (changed_roads, deleted_lanes, deleted_turns, added_turns, changed_intersections)
pub fn must_apply_edits(
&mut self,
new_edits: MapEdits,

View File

@ -9,7 +9,7 @@ use abstutil::{Tags, Timer};
use geom::{Bounds, Circle, Distance, PolyLine, Polygon, Pt2D};
pub use self::geometry::intersection_polygon;
use crate::make::initial::lane_specs::LaneSpec;
pub use crate::make::initial::lane_specs::LaneSpec;
use crate::raw::{OriginalRoad, RawMap, RawRoad};
use crate::{osm, IntersectionType, MapConfig};

View File

@ -11,8 +11,8 @@ use crate::pathfind::Pathfinder;
use crate::raw::{OriginalRoad, RawMap};
use crate::{
connectivity, osm, AccessRestrictions, Area, AreaID, AreaType, ControlStopSign,
ControlTrafficSignal, Direction, Intersection, IntersectionID, IntersectionType, Lane, LaneID,
Map, MapEdits, Movement, PathConstraints, Position, Road, RoadID, RoutingParams, Turn, Zone,
ControlTrafficSignal, Intersection, IntersectionID, IntersectionType, Lane, LaneID, Map,
MapEdits, Movement, PathConstraints, Position, Road, RoadID, RoutingParams, Turn, Zone,
};
mod bridges;
@ -99,7 +99,7 @@ impl Map {
}
timer.start_iter("expand roads to lanes", initial_map.roads.len());
for r in initial_map.roads.values() {
for (_, r) in initial_map.roads {
timer.next();
let road_id = road_id_mapping[&r.id];
@ -137,7 +137,7 @@ impl Map {
.collect(),
orig_id: r.id,
lanes_ltr: Vec::new(),
center_pts: r.trimmed_center_pts.clone(),
center_pts: r.trimmed_center_pts,
src_i: i1,
dst_i: i2,
speed_limit: Speed::ZERO,
@ -159,65 +159,13 @@ impl Map {
road.speed_limit = road.speed_limit_from_osm();
road.access_restrictions = road.access_restrictions_from_osm();
let mut total_back_width = Distance::ZERO;
for lane in &r.lane_specs_ltr {
if lane.dir == Direction::Back {
total_back_width += lane.width;
}
for lane in road.create_lanes(r.lane_specs_ltr, &mut map.lane_id_counter) {
map.intersections[lane.src_i.0].outgoing_lanes.push(lane.id);
map.intersections[lane.dst_i.0].incoming_lanes.push(lane.id);
road.lanes_ltr.push((lane.id, lane.dir, lane.lane_type));
map.lanes.insert(lane.id, lane);
}
// TODO Maybe easier to use the road's "yellow center line" and shift left/right from
// there.
let road_left_pts = road
.center_pts
.shift_left(r.half_width)
.unwrap_or_else(|_| road.center_pts.clone());
let mut width_so_far = Distance::ZERO;
for lane in &r.lane_specs_ltr {
let id = LaneID(map.lane_id_counter);
map.lane_id_counter += 1;
let (src_i, dst_i) = if lane.dir == Direction::Fwd {
(i1, i2)
} else {
(i2, i1)
};
map.intersections[src_i.0].outgoing_lanes.push(id);
map.intersections[dst_i.0].incoming_lanes.push(id);
road.lanes_ltr.push((id, lane.dir, lane.lt));
let pl =
if let Ok(pl) = road_left_pts.shift_right(width_so_far + (lane.width / 2.0)) {
pl
} else {
error!("{} geometry broken; lane not shifted!", id);
road_left_pts.clone()
};
let lane_center_pts = if lane.dir == Direction::Fwd {
pl
} else {
pl.reversed()
};
width_so_far += lane.width;
map.lanes.insert(
id,
Lane {
id,
lane_center_pts,
width: lane.width,
src_i,
dst_i,
lane_type: lane.lt,
dir: lane.dir,
parent: road_id,
bus_stops: BTreeSet::new(),
driving_blackhole: false,
biking_blackhole: false,
},
);
}
map.roads.push(road);
}

View File

@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use std::fmt;
use anyhow::Result;
@ -7,6 +8,7 @@ use serde::{Deserialize, Serialize};
use abstutil::{deserialize_usize, serialize_usize, Tags};
use geom::{Distance, PolyLine, Polygon, Speed};
use crate::make::initial::LaneSpec;
use crate::raw::{OriginalRoad, RestrictionType};
use crate::{
osm, AccessRestrictions, BusStopID, DrivingSide, IntersectionID, Lane, LaneID, LaneType, Map,
@ -455,6 +457,68 @@ impl Road {
pub fn is_extremely_short(&self) -> bool {
self.center_pts.length() < Distance::meters(2.0)
}
pub(crate) fn create_lanes(
&self,
lane_specs_ltr: Vec<LaneSpec>,
lane_id_counter: &mut usize,
) -> Vec<Lane> {
let mut total_back_width = Distance::ZERO;
let mut total_width = Distance::ZERO;
for lane in &lane_specs_ltr {
total_width += lane.width;
if lane.dir == Direction::Back {
total_back_width += lane.width;
}
}
// TODO Maybe easier to use the road's "yellow center line" and shift left/right from
// there.
let road_left_pts = self
.center_pts
.shift_left(total_width / 2.0)
.unwrap_or_else(|_| self.center_pts.clone());
let mut width_so_far = Distance::ZERO;
let mut lanes = Vec::new();
for lane in lane_specs_ltr {
let id = LaneID(*lane_id_counter);
*lane_id_counter += 1;
let (src_i, dst_i) = if lane.dir == Direction::Fwd {
(self.src_i, self.dst_i)
} else {
(self.dst_i, self.src_i)
};
let pl = if let Ok(pl) = road_left_pts.shift_right(width_so_far + (lane.width / 2.0)) {
pl
} else {
error!("{} geometry broken; lane not shifted!", id);
road_left_pts.clone()
};
let lane_center_pts = if lane.dir == Direction::Fwd {
pl
} else {
pl.reversed()
};
width_so_far += lane.width;
lanes.push(Lane {
id,
lane_center_pts,
width: lane.width,
src_i,
dst_i,
lane_type: lane.lt,
dir: lane.dir,
parent: self.id,
bus_stops: BTreeSet::new(),
driving_blackhole: false,
biking_blackhole: false,
});
}
lanes
}
}
// TODO All of this is kind of deprecated? During the transiton towards lanes_ltr, some pieces