Get rid of the now redundant lanes_ltr

This commit is contained in:
Dustin Carlino 2021-09-05 17:41:18 -07:00
parent 4c46510342
commit 112bc38e0c
29 changed files with 143 additions and 153 deletions

View File

@ -93,10 +93,9 @@ impl Isochrone {
let mut onstreet_parking_spots = 0; let mut onstreet_parking_spots = 0;
for r in all_roads { for r in all_roads {
let r = app.map.get_r(r); let r = app.map.get_r(r);
for (l, _, lt) in r.lanes_ltr() { for l in &r.lanes {
if lt == LaneType::Parking { if l.lane_type == LaneType::Parking {
onstreet_parking_spots += onstreet_parking_spots += l.number_parking_spots(app.map.get_config());
app.map.get_l(l).number_parking_spots(app.map.get_config());
} }
} }
} }

View File

@ -579,8 +579,10 @@ pub fn draw_unwalkable_roads(ctx: &mut EventCtx, app: &App, opts: &Options) -> D
if road.is_light_rail() { if road.is_light_rail() {
continue; continue;
} }
for (_, _, lt) in road.lanes_ltr() { for l in &road.lanes {
if lt == LaneType::Sidewalk || (lt == LaneType::Shoulder && allow_shoulders) { if l.lane_type == LaneType::Sidewalk
|| (l.lane_type == LaneType::Shoulder && allow_shoulders)
{
continue 'ROADS; continue 'ROADS;
} }
} }

View File

@ -183,7 +183,7 @@ fn inner_warp_to_id(ctx: &mut EventCtx, app: &mut App, line: &str) -> Option<Tra
Ok(idx) => match line.chars().next().unwrap() { Ok(idx) => match line.chars().next().unwrap() {
'r' => { 'r' => {
let r = app.primary.map.maybe_get_r(RoadID(idx))?; let r = app.primary.map.maybe_get_r(RoadID(idx))?;
ID::Lane(r.lanes_ltr()[0].0) ID::Lane(r.lanes[0].id)
} }
'R' => { 'R' => {
let r = BusRouteID(idx); let r = BusRouteID(idx);

View File

@ -784,8 +784,8 @@ impl ContextualActions for Actions {
if let Some((dist, _)) = pl.dist_along_of_point(pl.project_pt(pt)) { if let Some((dist, _)) = pl.dist_along_of_point(pl.project_pt(pt)) {
let base_pos = Position::new(l, dist); let base_pos = Position::new(l, dist);
let mut batch = GeomBatch::new(); let mut batch = GeomBatch::new();
for (l, _, _) in map.get_parent(l).lanes_ltr() { for l in &map.get_parent(l).lanes {
let pt = base_pos.equiv_pos(l, map).pt(map); let pt = base_pos.equiv_pos(l.id, map).pt(map);
batch.push( batch.push(
Color::RED, Color::RED,
Circle::new(pt, Distance::meters(1.0)).to_polygon(), Circle::new(pt, Distance::meters(1.0)).to_polygon(),
@ -891,14 +891,14 @@ fn find_degenerate_roads(app: &App) {
continue; continue;
} }
if r1 if r1
.lanes_ltr() .lanes
.into_iter() .iter()
.map(|(_, dir, lt)| (dir, lt)) .map(|l| (l.dir, l.lane_type))
.collect::<Vec<_>>() .collect::<Vec<_>>()
!= r2 != r2
.lanes_ltr() .lanes
.into_iter() .iter()
.map(|(_, dir, lt)| (dir, lt)) .map(|l| (l.dir, l.lane_type))
.collect::<Vec<_>>() .collect::<Vec<_>>()
{ {
continue; continue;

View File

@ -35,11 +35,11 @@ fn road(id: RoadID, map: &Map) -> Feature {
properties.insert("sharedstreetid".to_string(), id.0.into()); properties.insert("sharedstreetid".to_string(), id.0.into());
let mut slices = Vec::new(); let mut slices = Vec::new();
for (l, dir, _) in r.lanes_ltr() { for l in &r.lanes {
if let Some(mut slice) = lane(map.get_l(l)) { if let Some(mut slice) = lane(l) {
slice slice
.entry("direction".to_string()) .entry("direction".to_string())
.or_insert(if dir == Direction::Fwd { .or_insert(if l.dir == Direction::Fwd {
"forward".into() "forward".into()
} else { } else {
"reverse".into() "reverse".into()

View File

@ -15,8 +15,8 @@ fn road(id: RoadID, map: &Map) -> serde_json::Map<String, serde_json::value::Val
// TODO Many more fields // TODO Many more fields
let mut segments = Vec::new(); let mut segments = Vec::new();
for (l, dir, _) in r.lanes_ltr() { for l in &r.lanes {
segments.push(serde_json::value::Value::Object(lane(map.get_l(l), dir))); segments.push(serde_json::value::Value::Object(lane(l, l.dir)));
} }
street.insert( street.insert(
"segments".to_string(), "segments".to_string(),

View File

@ -80,7 +80,7 @@ impl RoadEditor {
} }
fn lane_for_idx(&self, app: &App, idx: usize) -> LaneID { fn lane_for_idx(&self, app: &App, idx: usize) -> LaneID {
app.primary.map.get_r(self.r).lanes_ltr()[idx].0 app.primary.map.get_r(self.r).lanes[idx].id
} }
fn modify_current_lane<F: Fn(&mut EditRoad, usize)>( fn modify_current_lane<F: Fn(&mut EditRoad, usize)>(
@ -316,9 +316,9 @@ impl State<App> for RoadEditor {
.primary .primary
.map .map
.get_r(self.r) .get_r(self.r)
.lanes_ltr() .lanes
.into_iter() .iter()
.all(|(_, _, lt)| lt != LaneType::Driving) .all(|l| l.lane_type != LaneType::Driving)
{ {
return Transition::Push(PopupMsg::new_state(ctx, "Error", vec!["Add a driving lane first. Parking can't exist without a way to access it."])); return Transition::Push(PopupMsg::new_state(ctx, "Error", vec!["Add a driving lane first. Parking can't exist without a way to access it."]));
} }
@ -553,7 +553,7 @@ fn make_main_panel(
let current_lt = selected_lane.map(|l| map.get_l(l).lane_type); let current_lt = selected_lane.map(|l| map.get_l(l).lane_type);
let current_lts: Vec<LaneType> = road.lanes_ltr().into_iter().map(|(_, _, lt)| lt).collect(); let current_lts: Vec<LaneType> = road.lanes.iter().map(|l| l.lane_type).collect();
let lane_types = [ let lane_types = [
(LaneType::Driving, Some(Key::D)), (LaneType::Driving, Some(Key::D)),
@ -628,10 +628,13 @@ fn make_main_panel(
let mut drag_drop = DragDrop::new(ctx, "lane cards", StackAxis::Horizontal); let mut drag_drop = DragDrop::new(ctx, "lane cards", StackAxis::Horizontal);
let road_width = road.get_width(); let road_width = road.get_width();
let lanes_ltr = road.lanes_ltr();
let lanes_len = lanes_ltr.len();
for (idx, (id, dir, lt)) in lanes_ltr.into_iter().enumerate() { for l in &road.lanes {
let idx = l.id.offset;
let id = l.id;
let dir = l.dir;
let lt = l.lane_type;
let mut icon_stack = GeomBatchStack::vertical(vec![ let mut icon_stack = GeomBatchStack::vertical(vec![
Image::from_path(lane_type_to_icon(lt).unwrap()) Image::from_path(lane_type_to_icon(lt).unwrap())
.dims((60.0, 50.0)) .dims((60.0, 50.0))
@ -664,7 +667,7 @@ fn make_main_panel(
if idx == 0 { if idx == 0 {
rounding.top_left = DEFAULT_CORNER_RADIUS; rounding.top_left = DEFAULT_CORNER_RADIUS;
} }
if idx == lanes_len - 1 { if idx == road.lanes.len() - 1 {
rounding.top_right = DEFAULT_CORNER_RADIUS; rounding.top_right = DEFAULT_CORNER_RADIUS;
} }
@ -786,7 +789,7 @@ fn make_main_panel(
ctx.style() ctx.style()
.btn_solid_destructive .btn_solid_destructive
.icon("system/assets/tools/trash.svg") .icon("system/assets/tools/trash.svg")
.disabled(road.lanes_ltr().len() == 1) .disabled(road.lanes.len() == 1)
.hotkey(Key::Backspace) .hotkey(Key::Backspace)
.build_widget(ctx, "delete lane") .build_widget(ctx, "delete lane")
.centered_vert(), .centered_vert(),
@ -1010,8 +1013,8 @@ fn draw_drop_position(app: &App, r: RoadID, from: usize, to: usize) -> GeomBatch
let map = &app.primary.map; let map = &app.primary.map;
let road = map.get_r(r); let road = map.get_r(r);
let take_num = if from < to { to + 1 } else { to }; let take_num = if from < to { to + 1 } else { to };
for (l, _, _) in road.lanes_ltr().into_iter().take(take_num) { for l in road.lanes.iter().take(take_num) {
width += map.get_l(l).width; width += l.width;
} }
if let Ok(pl) = road.get_left_side().shift_right(width) { if let Ok(pl) = road.get_left_side().shift_right(width) {
batch.push(app.cs.selected, pl.make_polygons(OUTLINE_THICKNESS)); batch.push(app.cs.selected, pl.make_polygons(OUTLINE_THICKNESS));

View File

@ -226,14 +226,14 @@ impl Snapper {
let mut incoming_pts = Vec::new(); let mut incoming_pts = Vec::new();
let mut outgoing_pts = Vec::new(); let mut outgoing_pts = Vec::new();
for (l, dir, lt) in r.lanes_ltr() { for l in &r.lanes {
if lt.is_walkable() { if l.lane_type.is_walkable() {
continue; continue;
} }
if dir == incoming_id.dir { if l.dir == incoming_id.dir {
incoming_pts.push(map.get_l(l).lane_center_pts.last_pt()); incoming_pts.push(l.lane_center_pts.last_pt());
} else { } else {
outgoing_pts.push(map.get_l(l).lane_center_pts.first_pt()); outgoing_pts.push(l.lane_center_pts.first_pt());
} }
} }

View File

@ -94,9 +94,9 @@ impl BikeActivity {
.primary .primary
.map .map
.get_r(*r) .get_r(*r)
.lanes_ltr() .lanes
.into_iter() .iter()
.any(|(_, _, lt)| lt == LaneType::Biking) .any(|l| l.lane_type == LaneType::Biking)
{ {
on_bike_lanes.add(*r, *count); on_bike_lanes.add(*r, *count);
} else { } else {

View File

@ -1062,16 +1062,16 @@ impl TutorialState {
)) ))
.unwrap(), .unwrap(),
); );
assert_eq!(r.lanes_ltr().len(), 6); assert_eq!(r.lanes.len(), 6);
r.lanes_ltr()[2].0 r.lanes[2].id
}; };
let lane_near_bldg = { let lane_near_bldg = {
let r = map.get_r( let r = map.get_r(
map.find_r_by_osm_id(OriginalRoad::new(6484869, (53163501, 53069236))) map.find_r_by_osm_id(OriginalRoad::new(6484869, (53163501, 53069236)))
.unwrap(), .unwrap(),
); );
assert_eq!(r.lanes_ltr().len(), 6); assert_eq!(r.lanes.len(), 6);
r.lanes_ltr()[3].0 r.lanes[3].id
}; };
let mut scenario = Scenario::empty(map, "prank"); let mut scenario = Scenario::empty(map, "prank");

View File

@ -61,10 +61,10 @@ impl DrawNetworkLayer {
for r in map.all_roads() { for r in map.all_roads() {
let mut bike_lane = false; let mut bike_lane = false;
let mut buffer = false; let mut buffer = false;
for (_, _, lt) in r.lanes_ltr() { for l in &r.lanes {
if lt == LaneType::Biking { if l.lane_type == LaneType::Biking {
bike_lane = true; bike_lane = true;
} else if matches!(lt, LaneType::Buffer(_)) { } else if matches!(l.lane_type, LaneType::Buffer(_)) {
buffer = true; buffer = true;
} }
} }

View File

@ -356,10 +356,10 @@ impl Layers {
let rank = r.get_rank(); let rank = r.get_rank();
let mut bike_lane = false; let mut bike_lane = false;
let mut buffer = false; let mut buffer = false;
for (_, _, lt) in r.lanes_ltr() { for l in &r.lanes {
if lt == LaneType::Biking { if l.lane_type == LaneType::Biking {
bike_lane = true; bike_lane = true;
} else if matches!(lt, LaneType::Buffer(_)) { } else if matches!(l.lane_type, LaneType::Buffer(_)) {
buffer = true; buffer = true;
} }
} }

View File

@ -396,11 +396,11 @@ fn calculate_border_arrows(i: &Intersection, r: &Road, map: &Map) -> Vec<Polygon
let mut width_fwd = Distance::ZERO; let mut width_fwd = Distance::ZERO;
let mut width_back = Distance::ZERO; let mut width_back = Distance::ZERO;
for (l, dir, _) in r.lanes_ltr() { for l in &r.lanes {
if dir == Direction::Fwd { if l.dir == Direction::Fwd {
width_fwd += map.get_l(l).width; width_fwd += l.width;
} else { } else {
width_back += map.get_l(l).width; width_back += l.width;
} }
} }
let center = r.get_dir_change_pl(map); let center = r.get_dir_change_pl(map);

View File

@ -281,17 +281,19 @@ fn calculate_parking_lines(lane: &Lane, map: &Map) -> Vec<Polygon> {
// Because the stripe straddles two lanes, it'll be partly hidden on one side. There are a bunch of // Because the stripe straddles two lanes, it'll be partly hidden on one side. There are a bunch of
// ways to work around this z-order issue. The current approach is to rely on the fact that // ways to work around this z-order issue. The current approach is to rely on the fact that
// quadtrees return LaneIDs in order, and lanes are always created from left->right. // quadtrees return LaneIDs in order, and lanes are always created from left->right.
fn calculate_driving_lines(lane: &Lane, parent: &Road) -> Vec<Polygon> { fn calculate_driving_lines(lane: &Lane, road: &Road) -> Vec<Polygon> {
let lanes = parent.lanes_ltr(); let idx = road.offset(lane.id);
let idx = parent.offset(lane.id);
// If the lane to the left of us isn't in the same direction or isn't the same type, don't // If the lane to the left of us isn't in the same direction or isn't the same type, don't
// need dashed lines. // need dashed lines.
if idx == 0 || lanes[idx].1 != lanes[idx - 1].1 || lanes[idx].2 != lanes[idx - 1].2 { if idx == 0
|| lane.dir != road.lanes[idx - 1].dir
|| lane.lane_type != road.lanes[idx - 1].lane_type
{
return Vec::new(); return Vec::new();
} }
let lane_edge_pts = if lanes[idx].1 == Direction::Fwd { let lane_edge_pts = if lane.dir == Direction::Fwd {
lane.lane_center_pts.must_shift_left(lane.width / 2.0) lane.lane_center_pts.must_shift_left(lane.width / 2.0)
} else { } else {
lane.lane_center_pts.must_shift_right(lane.width / 2.0) lane.lane_center_pts.must_shift_right(lane.width / 2.0)
@ -359,12 +361,12 @@ fn calculate_turn_markings(map: &Map, lane: &Lane) -> Vec<Polygon> {
results results
} }
fn calculate_one_way_markings(lane: &Lane, parent: &Road) -> Vec<Polygon> { fn calculate_one_way_markings(lane: &Lane, road: &Road) -> Vec<Polygon> {
let mut results = Vec::new(); let mut results = Vec::new();
let lanes = parent.lanes_ltr(); if road
if lanes .lanes
.into_iter() .iter()
.any(|(_, d, lt)| lane.dir != d && lt == LaneType::Driving) .any(|l| l.dir != lane.dir && l.lane_type == LaneType::Driving)
{ {
// Not a one-way // Not a one-way
return results; return results;

View File

@ -38,10 +38,12 @@ impl DrawRoad {
// Draw a center line every time two driving/bike/bus lanes of opposite direction are // Draw a center line every time two driving/bike/bus lanes of opposite direction are
// adjacent. // adjacent.
let mut width = Distance::ZERO; let mut width = Distance::ZERO;
for pair in r.lanes_ltr().windows(2) { for pair in r.lanes.windows(2) {
let ((l1, dir1, lt1), (_, dir2, lt2)) = (pair[0], pair[1]); width += pair[0].width;
width += app.map().get_l(l1).width; if pair[0].dir != pair[1].dir
if dir1 != dir2 && lt1.is_for_moving_vehicles() && lt2.is_for_moving_vehicles() { && pair[0].lane_type.is_for_moving_vehicles()
&& pair[1].lane_type.is_for_moving_vehicles()
{
let pl = r.get_left_side().must_shift_right(width); let pl = r.get_left_side().must_shift_right(width);
batch.extend( batch.extend(
center_line_color, center_line_color,

View File

@ -119,9 +119,8 @@ pub fn all_walking_costs_from(
let mut shoulder_endpoint = Vec::new(); let mut shoulder_endpoint = Vec::new();
for q in &queue { for q in &queue {
if let WalkingNode::SidewalkEndpoint(dir_r, _) = q.node { if let WalkingNode::SidewalkEndpoint(dir_r, _) = q.node {
let lanes = &map.get_r(dir_r.id).lanes_ltr; for lane in &map.get_r(dir_r.id).lanes {
for (_, _, lane_type) in lanes { shoulder_endpoint.push(lane.lane_type == LaneType::Shoulder);
shoulder_endpoint.push(lane_type == &LaneType::Shoulder)
} }
} }
} }

View File

@ -392,7 +392,7 @@ fn fix_lane_widths(value: &mut Value, map: &Map) -> Result<()> {
dir, dir,
// Before this commit, lane widths weren't modifiable, so this lookup works // Before this commit, lane widths weren't modifiable, so this lookup works
// for both "old" and "new". // for both "old" and "new".
width: map.get_l(road.lanes_ltr()[idx].0).width, width: road.lanes[idx].width,
}); });
} }
cmd[key]["lanes_ltr"] = serde_json::to_value(lanes_ltr).unwrap(); cmd[key]["lanes_ltr"] = serde_json::to_value(lanes_ltr).unwrap();

View File

@ -326,15 +326,14 @@ impl MapEdits {
{ {
roads.insert(r.id); roads.insert(r.id);
} else { } else {
let lanes_ltr = r.lanes_ltr(); if r.lanes.len() != orig.lanes_ltr.len() {
if lanes_ltr.len() != orig.lanes_ltr.len() {
// If a lane was added or deleted, figuring out if any were modified is kind of // If a lane was added or deleted, figuring out if any were modified is kind of
// unclear -- just mark the entire road. // unclear -- just mark the entire road.
roads.insert(r.id); roads.insert(r.id);
} else { } else {
for ((l, dir, lt), spec) in lanes_ltr.into_iter().zip(orig.lanes_ltr.iter()) { for (l, spec) in r.lanes.iter().zip(orig.lanes_ltr.iter()) {
if dir != spec.dir || lt != spec.lt || map.get_l(l).width != spec.width { if l.dir != spec.dir || l.lane_type != spec.lt || l.width != spec.width {
lanes.insert(l); lanes.insert(l.id);
} }
} }
} }

View File

@ -93,7 +93,7 @@ impl PermanentEditCmd {
match self { match self {
PermanentEditCmd::ChangeRoad { r, new, old } => { PermanentEditCmd::ChangeRoad { r, new, old } => {
let id = map.find_r_by_osm_id(r)?; let id = map.find_r_by_osm_id(r)?;
let num_current = map.get_r(id).lanes_ltr().len(); let num_current = map.get_r(id).lanes.len();
// The basemap changed -- it'd be pretty hard to understand the original // The basemap changed -- it'd be pretty hard to understand the original
// intent of the edit. // intent of the edit.
if num_current != old.lanes_ltr.len() { if num_current != old.lanes_ltr.len() {

View File

@ -15,8 +15,7 @@ pub fn find_medians(map: &Map) -> Vec<Polygon> {
for r in map.all_roads() { for r in map.all_roads() {
if r.osm_tags.is("dual_carriageway", "yes") { if r.osm_tags.is("dual_carriageway", "yes") {
// TODO Always to the left? Maybe driving side matters; test in southbank too // TODO Always to the left? Maybe driving side matters; test in southbank too
let lanes_ltr = r.lanes_ltr(); candidates.push(r.lanes[0].id);
candidates.push(lanes_ltr[0].0);
} }
} }

View File

@ -150,7 +150,6 @@ impl Map {
.collect(), .collect(),
orig_id: r.id, orig_id: r.id,
lanes: Vec::new(), lanes: Vec::new(),
lanes_ltr: Vec::new(),
center_pts: r.trimmed_center_pts, center_pts: r.trimmed_center_pts,
untrimmed_center_pts: raw_road.get_geometry(r.id, map.get_config()).unwrap().0, untrimmed_center_pts: raw_road.get_geometry(r.id, map.get_config()).unwrap().0,
src_i: i1, src_i: i1,

View File

@ -209,15 +209,15 @@ fn make_walking_turns_v2(map: &Map, i: &Intersection) -> Vec<Turn> {
} }
for r in sorted_roads { for r in sorted_roads {
let r = map.get_r(r); let road = map.get_r(r);
let mut fwd = None; let mut fwd = None;
let mut back = None; let mut back = None;
for (l, dir, lt) in r.lanes_ltr() { for l in &road.lanes {
if lt.is_walkable() { if l.lane_type.is_walkable() {
if dir == Direction::Fwd { if l.dir == Direction::Fwd {
fwd = Some(map.get_l(l)); fwd = Some(l);
} else { } else {
back = Some(map.get_l(l)); back = Some(l);
} }
} }
} }
@ -227,7 +227,7 @@ fn make_walking_turns_v2(map: &Map, i: &Intersection) -> Vec<Turn> {
if back.is_some() { if back.is_some() {
num_sidewalks += 1; num_sidewalks += 1;
} }
let (in_lane, out_lane) = if r.src_i == i.id { let (in_lane, out_lane) = if road.src_i == i.id {
(back, fwd) (back, fwd)
} else { } else {
(fwd, back) (fwd, back)

View File

@ -23,8 +23,8 @@ const SHOULDER_THICKNESS: Distance = Distance::const_meters(0.5);
/// A lane is identified by its parent road and its position, ordered from the left. /// A lane is identified by its parent road and its position, ordered from the left.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct LaneID { pub struct LaneID {
pub(crate) road: RoadID, pub road: RoadID,
pub(crate) offset: usize, pub offset: usize,
} }
impl fmt::Display for LaneID { impl fmt::Display for LaneID {
@ -445,7 +445,7 @@ impl Lane {
let start = self.id; let start = self.id;
let mut pts = Vec::new(); let mut pts = Vec::new();
let mut current = start; let mut current = start;
let mut fwd = map.get_parent(start).lanes_ltr()[0].0 == start; let mut fwd = map.get_parent(start).lanes[0].id == start;
let mut visited = BTreeSet::new(); let mut visited = BTreeSet::new();
loop { loop {
let l = map.get_l(current); let l = map.get_l(current);
@ -484,9 +484,9 @@ impl Lane {
// Depending on if this road points to or from the intersection, get the left- or // Depending on if this road points to or from the intersection, get the left- or
// right-most lane. // right-most lane.
let next_lane = if next_road.src_i == i { let next_lane = if next_road.src_i == i {
next_road.lanes_ltr()[0].0 next_road.lanes[0].id
} else { } else {
next_road.lanes_ltr().last().unwrap().0 next_road.lanes.last().unwrap().id
}; };
if next_lane == start { if next_lane == start {
break; break;

View File

@ -147,10 +147,9 @@ pub struct Road {
/// positive is uphill from src_i -> dst_i, negative is downhill. /// positive is uphill from src_i -> dst_i, negative is downhill.
pub percent_incline: f64, pub percent_incline: f64,
/// Invariant: A road must contain at least one child. These are ordered from left-to-right. /// Invariant: A road must contain at least one child. These are ordered from the left side of
/// the road to the right, with that orientation determined by the direction of `center_pts`.
pub lanes: Vec<Lane>, pub lanes: Vec<Lane>,
// TODO Remove -- this becomes redundant
pub(crate) lanes_ltr: Vec<(LaneID, Direction, LaneType)>,
/// The physical center of the road, including sidewalks, after trimming to account for the /// The physical center of the road, including sidewalks, after trimming to account for the
/// intersection geometry. The order implies road orientation. /// intersection geometry. The order implies road orientation.
@ -163,13 +162,6 @@ pub struct Road {
} }
impl Road { impl Road {
/// Returns all lanes from the left side of the road to right. Left/right is determined by the
/// orientation of center_pts.
pub fn lanes_ltr(&self) -> Vec<(LaneID, Direction, LaneType)> {
// TODO Change this to return &Vec
self.lanes_ltr.clone()
}
pub(crate) fn lane_specs(&self) -> Vec<LaneSpec> { pub(crate) fn lane_specs(&self) -> Vec<LaneSpec> {
self.lanes self.lanes
.iter() .iter()
@ -188,13 +180,11 @@ impl Road {
/// Counting from the left side of the road /// Counting from the left side of the road
pub fn offset(&self, lane: LaneID) -> usize { pub fn offset(&self, lane: LaneID) -> usize {
for (idx, (l, _, _)) in self.lanes_ltr().into_iter().enumerate() { match self.lanes.iter().position(|l| l.id == lane) {
if lane == l { Some(x) => x,
return idx; None => panic!("{} doesn't contain {}", self.id, lane),
} }
} }
panic!("{} doesn't contain {}", self.id, lane);
}
/// lane must belong to this road. Offset 0 is the centermost lane on each side of a road, then /// lane must belong to this road. Offset 0 is the centermost lane on each side of a road, then
/// it counts up from there. Note this is a different offset than `offset`! /// it counts up from there. Note this is a different offset than `offset`!
@ -409,11 +399,11 @@ impl Road {
} }
pub fn is_light_rail(&self) -> bool { pub fn is_light_rail(&self) -> bool {
self.lanes_ltr().len() == 1 && self.lanes_ltr()[0].2 == LaneType::LightRail self.lanes.len() == 1 && self.lanes[0].lane_type == LaneType::LightRail
} }
pub fn is_footway(&self) -> bool { pub fn is_footway(&self) -> bool {
self.lanes_ltr().len() == 1 && self.lanes_ltr()[0].2 == LaneType::Sidewalk self.lanes.len() == 1 && self.lanes[0].lane_type == LaneType::Sidewalk
} }
pub fn is_service(&self) -> bool { pub fn is_service(&self) -> bool {
@ -422,10 +412,10 @@ impl Road {
pub fn is_cycleway(&self) -> bool { pub fn is_cycleway(&self) -> bool {
let mut bike = false; let mut bike = false;
for (_, _, lt) in self.lanes_ltr() { for lane in &self.lanes {
if lt == LaneType::Biking { if lane.lane_type == LaneType::Biking {
bike = true; bike = true;
} else if lt != LaneType::Shoulder { } else if lane.lane_type != LaneType::Shoulder {
return false; return false;
} }
} }
@ -509,7 +499,6 @@ impl Road {
pub(crate) fn recreate_lanes(&mut self, lane_specs_ltr: Vec<LaneSpec>) { pub(crate) fn recreate_lanes(&mut self, lane_specs_ltr: Vec<LaneSpec>) {
self.lanes.clear(); self.lanes.clear();
self.lanes_ltr.clear();
let mut total_width = Distance::ZERO; let mut total_width = Distance::ZERO;
for lane in &lane_specs_ltr { for lane in &lane_specs_ltr {
@ -548,8 +537,6 @@ impl Road {
}; };
width_so_far += lane.width; width_so_far += lane.width;
// TODO Revisit
self.lanes_ltr.push((id, lane.dir, lane.lt));
self.lanes.push(Lane { self.lanes.push(Lane {
id, id,
lane_center_pts, lane_center_pts,
@ -570,13 +557,13 @@ impl Road {
pub fn get_lanes_between(&self, l1: LaneID, l2: LaneID) -> Vec<LaneID> { pub fn get_lanes_between(&self, l1: LaneID, l2: LaneID) -> Vec<LaneID> {
let mut results = Vec::new(); let mut results = Vec::new();
let mut found_start = false; let mut found_start = false;
for (l, _, _) in self.lanes_ltr() { for l in &self.lanes {
if found_start { if found_start {
if l == l1 || l == l2 { if l.id == l1 || l.id == l2 {
return results; return results;
} }
results.push(l); results.push(l.id);
} else if l == l1 || l == l2 { } else if l.id == l1 || l.id == l2 {
found_start = true; found_start = true;
} }
} }
@ -594,11 +581,11 @@ impl Road {
let mut bike_lanes = false; let mut bike_lanes = false;
let mut can_use = false; let mut can_use = false;
// Can a bike even use it, or is it a highway? // Can a bike even use it, or is it a highway?
for (l, _, lt) in self.lanes_ltr() { for l in &self.lanes {
if lt == LaneType::Biking { if l.lane_type == LaneType::Biking {
bike_lanes = true; bike_lanes = true;
} }
if PathConstraints::Bike.can_use(map.get_l(l), map) { if PathConstraints::Bike.can_use(l, map) {
can_use = true; can_use = true;
} }
} }
@ -609,26 +596,26 @@ impl Road {
} }
} }
// TODO All of this is kind of deprecated? During the transiton towards lanes_ltr, some pieces // TODO All of this is kind of deprecated? Some callers seem to really need to still handle lanes
// seemed to really need to still handle lanes going outward from the "center" line. Should keep // going outward from the "center" line. Should keep whittling this down, probably. These very much
// whittling this down, probably. These very much don't handle multiple direction changes. // don't handle multiple direction changes.
impl Road { impl Road {
/// These are ordered from closest to center lane (left-most when driving on the right) to /// These are ordered from closest to center lane (left-most when driving on the right) to
/// farthest (sidewalk) /// farthest (sidewalk)
pub(crate) fn children_forwards(&self) -> Vec<(LaneID, LaneType)> { pub(crate) fn children_forwards(&self) -> Vec<(LaneID, LaneType)> {
let mut result = Vec::new(); let mut result = Vec::new();
for (l, dir, lt) in self.lanes_ltr() { for l in &self.lanes {
if dir == Direction::Fwd { if l.dir == Direction::Fwd {
result.push((l, lt)); result.push((l.id, l.lane_type));
} }
} }
result result
} }
pub(crate) fn children_backwards(&self) -> Vec<(LaneID, LaneType)> { pub(crate) fn children_backwards(&self) -> Vec<(LaneID, LaneType)> {
let mut result = Vec::new(); let mut result = Vec::new();
for (l, dir, lt) in self.lanes_ltr() { for l in &self.lanes {
if dir == Direction::Back { if l.dir == Direction::Back {
result.push((l, lt)); result.push((l.id, l.lane_type));
} }
} }
result.reverse(); result.reverse();

View File

@ -65,11 +65,11 @@ impl ControlStopSign {
Direction::Back Direction::Back
}; };
let travel_lanes: Vec<LaneID> = r let travel_lanes: Vec<LaneID> = r
.lanes_ltr() .lanes
.into_iter() .iter()
.filter_map(|(id, dir, lt)| { .filter_map(|l| {
if dir == want_dir && lt.is_for_moving_vehicles() { if l.dir == want_dir && l.lane_type.is_for_moving_vehicles() {
Some(id) Some(l.id)
} else { } else {
None None
} }

View File

@ -364,10 +364,10 @@ impl Movement {
let mut rightmost = Distance::ZERO; let mut rightmost = Distance::ZERO;
let mut left = Distance::ZERO; let mut left = Distance::ZERO;
for (l, _, _) in r.lanes_ltr() { for l in &r.lanes {
let right = left + map.get_l(l).width; let right = left + l.width;
if self.members.iter().any(|t| t.src == l) { if self.members.iter().any(|t| t.src == l.id) {
leftmost = leftmost.min(left); leftmost = leftmost.min(left);
rightmost = rightmost.max(right); rightmost = rightmost.max(right);
} }

View File

@ -205,8 +205,8 @@ impl Player {
On::Intersection(i) => app.map.get_i(i).roads.iter().cloned().collect(), On::Intersection(i) => app.map.get_i(i).roads.iter().cloned().collect(),
}; };
for r in roads { for r in roads {
for (_, _, lt) in app.map.get_r(r).lanes_ltr() { for l in &app.map.get_r(r).lanes {
if lt == LaneType::Biking || lt == LaneType::Bus { if l.lane_type == LaneType::Biking || l.lane_type == LaneType::Bus {
return true; return true;
} }
} }

View File

@ -1083,14 +1083,13 @@ impl DrivingSimState {
let current_lane = map.get_l(car.router.head().maybe_lane()?); let current_lane = map.get_l(car.router.head().maybe_lane()?);
let road = map.get_r(current_lane.parent); let road = map.get_r(current_lane.parent);
let idx = road.offset(current_lane.id); let idx = road.offset(current_lane.id);
let lanes_ltr = road.lanes_ltr();
let mut candidates = Vec::new(); let mut candidates = Vec::new();
if idx != 0 { if idx != 0 {
candidates.push(lanes_ltr[idx - 1].0); candidates.push(road.lanes[idx - 1].id);
} }
if idx != lanes_ltr.len() - 1 { if idx != road.lanes.len() - 1 {
candidates.push(lanes_ltr[idx + 1].0); candidates.push(road.lanes[idx + 1].id);
} }
if map.get_config().driving_side == DrivingSide::Left { if map.get_config().driving_side == DrivingSide::Left {
candidates.reverse(); candidates.reverse();

View File

@ -399,27 +399,27 @@ impl Router {
let mut original_cost = None; let mut original_cost = None;
let dir = map.get_l(orig_target_lane).dir; let dir = map.get_l(orig_target_lane).dir;
let best = parent let best = parent
.lanes_ltr() .lanes
.into_iter() .iter()
.filter(|(l, d, _)| dir == *d && constraints.can_use(map.get_l(*l), map)) .filter(|l| l.dir == dir && constraints.can_use(l, map))
.filter_map(|(l, _, _)| { .filter_map(|l| {
// Make sure we can go from this lane to next_lane. // Make sure we can go from this lane to next_lane.
let t1 = TurnID { let t1 = TurnID {
parent: current_turn.parent, parent: current_turn.parent,
src: current_turn.src, src: current_turn.src,
dst: l, dst: l.id,
}; };
let turn1 = map.maybe_get_t(t1)?; let turn1 = map.maybe_get_t(t1)?;
let t2 = TurnID { let t2 = TurnID {
parent: next_parent, parent: next_parent,
src: l, src: l.id,
dst: next_lane, dst: next_lane,
}; };
let turn2 = map.maybe_get_t(t2)?; let turn2 = map.maybe_get_t(t2)?;
Some((turn1, l, turn2)) Some((turn1, l.id, turn2))
}) })
.map(|(turn1, l, turn2)| { .map(|(turn1, l, turn2)| {
let cost = compute_cost(turn1, l); let cost = compute_cost(turn1, l);