Change how non-driveable roads (cycleways) work in the LTN tool and

blockfinding. Stop using them as parts of block boundaries, and stop
drawing special "car-free" cells around them.

Motivation in the PR description.
This commit is contained in:
Dustin Carlino 2022-05-17 10:47:24 +01:00
parent a60104762e
commit a56f47bfaf
6 changed files with 543 additions and 581 deletions

View File

@ -30,7 +30,6 @@ lazy_static::lazy_static! {
pub static ref PLAN_ROUTE_WALK: Color = Color::BLUE; pub static ref PLAN_ROUTE_WALK: Color = Color::BLUE;
} }
pub const CAR_FREE_CELL: Color = Color::GREEN.alpha(0.5);
pub const DISCONNECTED_CELL: Color = Color::RED.alpha(0.5); pub const DISCONNECTED_CELL: Color = Color::RED.alpha(0.5);
pub const OUTLINE: Color = Color::BLACK; pub const OUTLINE: Color = Color::BLACK;

View File

@ -138,11 +138,9 @@ impl RenderCellsBuilder {
let adjacencies = diffusion(&mut grid, boundary_marker); let adjacencies = diffusion(&mut grid, boundary_marker);
let mut cell_colors = color_cells(neighborhood.cells.len(), adjacencies); let mut cell_colors = color_cells(neighborhood.cells.len(), adjacencies);
// Color car-free cells in a special way // Color some special cells
for (idx, cell) in neighborhood.cells.iter().enumerate() { for (idx, cell) in neighborhood.cells.iter().enumerate() {
if cell.car_free { if cell.is_disconnected() {
cell_colors[idx] = colors::CAR_FREE_CELL;
} else if cell.is_disconnected() {
cell_colors[idx] = colors::DISCONNECTED_CELL; cell_colors[idx] = colors::DISCONNECTED_CELL;
} }
} }

View File

@ -34,15 +34,12 @@ pub struct Cell {
pub roads: BTreeMap<RoadID, DistanceInterval>, pub roads: BTreeMap<RoadID, DistanceInterval>,
/// Intersections where this cell touches the boundary of the neighborhood. /// Intersections where this cell touches the boundary of the neighborhood.
pub borders: BTreeSet<IntersectionID>, pub borders: BTreeSet<IntersectionID>,
/// This cell only contains roads that ban cars.
pub car_free: bool,
} }
impl Cell { impl Cell {
/// A cell is disconnected if it's not connected to a perimeter road. (The exception is cells /// A cell is disconnected if it's not connected to a perimeter road.
/// containing roads that by their OSM classification already ban cars.)
pub fn is_disconnected(&self) -> bool { pub fn is_disconnected(&self) -> bool {
self.borders.is_empty() && !self.car_free self.borders.is_empty()
} }
} }
@ -141,14 +138,13 @@ fn find_cells(
let mut cells = Vec::new(); let mut cells = Vec::new();
let mut visited = BTreeSet::new(); let mut visited = BTreeSet::new();
let mut no_car_roads = Vec::new();
for start in &perimeter.interior { for start in &perimeter.interior {
if visited.contains(start) || modal_filters.roads.contains_key(start) { if visited.contains(start) || modal_filters.roads.contains_key(start) {
continue; continue;
} }
let start = *start; let start = *start;
// Just skip entirely; they're invisible for the purpose of dividing into cells
if !PathConstraints::Car.can_use_road(map.get_r(start), map) { if !PathConstraints::Car.can_use_road(map.get_r(start), map) {
no_car_roads.push(start);
continue; continue;
} }
let cell = floodfill(map, start, borders, &modal_filters); let cell = floodfill(map, start, borders, &modal_filters);
@ -163,7 +159,6 @@ fn find_cells(
let mut cell = Cell { let mut cell = Cell {
roads: BTreeMap::new(), roads: BTreeMap::new(),
borders: btreeset! { road.src_i }, borders: btreeset! { road.src_i },
car_free: false,
}; };
cell.roads.insert( cell.roads.insert(
road.id, road.id,
@ -178,7 +173,6 @@ fn find_cells(
let mut cell = Cell { let mut cell = Cell {
roads: BTreeMap::new(), roads: BTreeMap::new(),
borders: btreeset! { road.dst_i }, borders: btreeset! { road.dst_i },
car_free: false,
}; };
cell.roads.insert( cell.roads.insert(
road.id, road.id,
@ -191,34 +185,6 @@ fn find_cells(
} }
} }
// Roads already banning cars should still contribute a cell, so the cell coloring can still
// account for them
//
// TODO Should we attempt to merge adjacent cells like this? If we have lots of tiny pieces of
// bike-only roads, they'll each get their own cell
for r in no_car_roads {
let mut cell = Cell {
roads: BTreeMap::new(),
borders: BTreeSet::new(),
car_free: true,
};
let road = map.get_r(r);
if borders.contains(&road.src_i) {
cell.borders.insert(road.src_i);
}
if borders.contains(&road.dst_i) {
cell.borders.insert(road.dst_i);
}
cell.roads.insert(
road.id,
DistanceInterval {
start: Distance::ZERO,
end: road.length(),
},
);
cells.push(cell);
}
cells cells
} }
@ -310,6 +276,5 @@ fn floodfill(
Cell { Cell {
roads: visited_roads, roads: visited_roads,
borders: cell_borders, borders: cell_borders,
car_free: false,
} }
} }

View File

@ -7,7 +7,9 @@ use serde::{Deserialize, Serialize};
use abstutil::wraparound_get; use abstutil::wraparound_get;
use geom::{Polygon, Pt2D, Ring}; use geom::{Polygon, Pt2D, Ring};
use crate::{CommonEndpoint, Direction, LaneID, Map, RoadID, RoadSideID, SideOfRoad}; use crate::{
CommonEndpoint, Direction, LaneID, Map, PathConstraints, RoadID, RoadSideID, SideOfRoad,
};
/// A block is defined by a perimeter that traces along the sides of roads. Inside the perimeter, /// A block is defined by a perimeter that traces along the sides of roads. Inside the perimeter,
/// the block may contain buildings and interior roads. In the simple case, a block represents a /// the block may contain buildings and interior roads. In the simple case, a block represents a
@ -120,15 +122,16 @@ impl Perimeter {
perimeters perimeters
} }
/// Trying to form blocks near railways or cycleways that involve bridges/tunnels often causes /// Blockfinding is specialized for the LTN tool, so non-driveable roads (cycleways and light
/// overlapping geometry or blocks that're way too large. These are extremely imperfect /// rail) are considered invisible and can't be on a perimeter. Previously, there were also
/// heuristics to avoid the worst problems. /// some heuristics here to try to skip certain bridges/tunnels that break the planarity of
/// blocks.
pub fn find_roads_to_skip_tracing(map: &Map) -> HashSet<RoadID> { pub fn find_roads_to_skip_tracing(map: &Map) -> HashSet<RoadID> {
let mut skip = HashSet::new(); let mut skip = HashSet::new();
for r in map.all_roads() { for r in map.all_roads() {
if r.is_light_rail() { if r.is_light_rail() {
skip.insert(r.id); skip.insert(r.id);
} else if r.is_cycleway() && r.zorder != 0 { } else if !PathConstraints::Car.can_use_road(r, map) {
skip.insert(r.id); skip.insert(r.id);
} }
} }

View File

@ -1,22 +1,22 @@
data/system/us/seattle/maps/montlake.bin data/system/us/seattle/maps/montlake.bin
177 single blocks (0 failures to blockify), 1 partial merges, 0 failures to blockify partitions 160 single blocks (0 failures to blockify), 0 partial merges, 0 failures to blockify partitions
data/system/us/seattle/maps/downtown.bin data/system/us/seattle/maps/downtown.bin
1526 single blocks (0 failures to blockify), 10 partial merges, 0 failures to blockify partitions 1309 single blocks (0 failures to blockify), 1 partial merges, 0 failures to blockify partitions
data/system/us/seattle/maps/lakeslice.bin data/system/us/seattle/maps/lakeslice.bin
1063 single blocks (0 failures to blockify), 1 partial merges, 0 failures to blockify partitions 1009 single blocks (0 failures to blockify), 1 partial merges, 0 failures to blockify partitions
data/system/us/phoenix/maps/tempe.bin data/system/us/phoenix/maps/tempe.bin
425 single blocks (1 failures to blockify), 0 partial merges, 0 failures to blockify partitions 419 single blocks (1 failures to blockify), 0 partial merges, 0 failures to blockify partitions
data/system/gb/bristol/maps/east.bin data/system/gb/bristol/maps/east.bin
1059 single blocks (3 failures to blockify), 6 partial merges, 0 failures to blockify partitions 822 single blocks (3 failures to blockify), 2 partial merges, 0 failures to blockify partitions
data/system/gb/leeds/maps/north.bin data/system/gb/leeds/maps/north.bin
2597 single blocks (5 failures to blockify), 17 partial merges, 1 failures to blockify partitions 1936 single blocks (1 failures to blockify), 6 partial merges, 1 failures to blockify partitions
data/system/gb/london/maps/camden.bin data/system/gb/london/maps/camden.bin
1565 single blocks (1 failures to blockify), 5 partial merges, 0 failures to blockify partitions 1046 single blocks (2 failures to blockify), 3 partial merges, 0 failures to blockify partitions
data/system/gb/london/maps/southwark.bin data/system/gb/london/maps/southwark.bin
2195 single blocks (3 failures to blockify), 11 partial merges, 1 failures to blockify partitions 1326 single blocks (1 failures to blockify), 5 partial merges, 1 failures to blockify partitions
data/system/gb/manchester/maps/levenshulme.bin data/system/gb/manchester/maps/levenshulme.bin
1353 single blocks (1 failures to blockify), 0 partial merges, 0 failures to blockify partitions 1244 single blocks (1 failures to blockify), 0 partial merges, 0 failures to blockify partitions
data/system/fr/lyon/maps/center.bin data/system/fr/lyon/maps/center.bin
5216 single blocks (5 failures to blockify), 26 partial merges, 1 failures to blockify partitions 3818 single blocks (3 failures to blockify), 12 partial merges, 0 failures to blockify partitions
data/system/us/seattle/maps/north_seattle.bin data/system/us/seattle/maps/north_seattle.bin
3418 single blocks (1 failures to blockify), 6 partial merges, 1 failures to blockify partitions 3286 single blocks (1 failures to blockify), 7 partial merges, 0 failures to blockify partitions

File diff suppressed because it is too large Load Diff