Scrape bollards defined as OSM nodes, and plumb through to the LTN tool.

The approach is a bit brittle, but works fine in Bristol.

Regenerating everything...
This commit is contained in:
Dustin Carlino 2022-06-28 20:23:55 -05:00
parent f8d30c411f
commit 7af2c028fc
8 changed files with 1536 additions and 1472 deletions

View File

@ -60,6 +60,13 @@ pub fn transform_existing_filters(ctx: &EventCtx, app: &mut App, timer: &mut Tim
.roads
.insert(r, app.map.get_r(r).length() / 2.0);
}
// The new, kind of simpler case
for r in app.map.all_roads() {
for dist in &r.barrier_nodes {
app.session.modal_filters.roads.insert(r.id, *dist);
}
}
}
fn detect_filters(map: &Map) -> Vec<&Road> {

View File

@ -28,6 +28,9 @@ pub struct OsmExtract {
pub amenities: Vec<(Pt2D, Amenity)>,
/// Crosswalks located at these points, which should be on a RawRoad's center line
pub crosswalks: HashSet<HashablePt2D>,
/// Some kind of barrier nodes at these points. Only the ones on a RawRoad center line are
/// relevant.
pub barrier_nodes: HashSet<HashablePt2D>,
}
pub fn extract_osm(
@ -66,6 +69,7 @@ pub fn extract_osm(
complicated_turn_restrictions: Vec::new(),
amenities: Vec::new(),
crosswalks: HashSet::new(),
barrier_nodes: HashSet::new(),
};
timer.start_iter("processing OSM nodes", doc.nodes.len());
@ -84,6 +88,10 @@ pub fn extract_osm(
if node.tags.is(osm::HIGHWAY, "crossing") {
out.crosswalks.insert(node.pt.to_hashable());
}
// TODO Any kind of barrier?
if node.tags.is("barrier", "bollard") {
out.barrier_nodes.insert(node.pt.to_hashable());
}
for amenity in get_bldg_amenities(&node.tags) {
out.amenities.push((node.pt, amenity));
}

View File

@ -132,6 +132,12 @@ pub fn convert(
parking::apply_parking(&mut map, &opts, timer);
use_barrier_nodes(
&mut map,
split_output.barrier_nodes,
&split_output.pt_to_road,
);
if opts.elevation {
timer.start("add elevation data");
if let Err(err) = elevation::add_data(&mut map) {
@ -251,6 +257,22 @@ fn filter_crosswalks(
}
}
fn use_barrier_nodes(
map: &mut RawMap,
barrier_nodes: HashSet<HashablePt2D>,
pt_to_road: &HashMap<HashablePt2D, OriginalRoad>,
) {
for pt in barrier_nodes {
// Many barriers are on footpaths or roads that we don't retain
if let Some(road) = pt_to_road.get(&pt).and_then(|r| map.roads.get_mut(r)) {
// Filters on roads that're already car-free are redundant
if road.is_driveable() {
road.barrier_nodes.push(pt.to_pt2d());
}
}
}
}
// We're using Bristol for a project that requires an unusual LTN neighborhood boundary. Insert a
// fake road where a bridge crosses another road, to force blockfinding to trace along there.
fn bristol_hack(map: &mut RawMap) {

View File

@ -11,6 +11,7 @@ use crate::extract::OsmExtract;
pub struct Output {
pub amenities: Vec<(Pt2D, Amenity)>,
pub crosswalks: HashSet<HashablePt2D>,
pub barrier_nodes: HashSet<HashablePt2D>,
/// A mapping of all points to the split road. Some internal points on roads get removed in
/// `split_up_roads`, so this mapping isn't redundant.
pub pt_to_road: HashMap<HashablePt2D, OriginalRoad>,
@ -222,6 +223,7 @@ pub fn split_up_roads(map: &mut RawMap, mut input: OsmExtract, timer: &mut Timer
Output {
amenities: input.amenities,
crosswalks: input.crosswalks,
barrier_nodes: input.barrier_nodes,
pt_to_road,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,9 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use structopt::StructOpt;
use abstutil::{MultiMap, Timer};
use geom::{Distance, FindClosest, HashablePt2D, Line, Polygon, Speed, EPSILON_DIST};
use geom::{
Distance, FindClosest, HashablePt2D, Line, PolyLine, Polygon, Pt2D, Speed, EPSILON_DIST,
};
use raw_map::initial;
pub use self::parking_lots::snap_driveway;
@ -111,6 +113,7 @@ impl Map {
let i2 = intersection_id_mapping[&r.dst_i];
let raw_road = &raw.roads[&r.id];
let barrier_nodes = snap_nodes_to_line(&raw_road.barrier_nodes, &r.trimmed_center_pts);
let mut road = Road {
id: road_id,
osm_tags: raw_road.osm_tags.clone(),
@ -152,6 +155,7 @@ impl Map {
crosswalk_forward: raw_road.crosswalk_forward,
crosswalk_backward: raw_road.crosswalk_backward,
transit_stops: BTreeSet::new(),
barrier_nodes,
};
road.speed_limit = road.speed_limit_from_osm();
road.access_restrictions = road.access_restrictions_from_osm();
@ -373,3 +377,15 @@ pub fn trim_path(poly: &Polygon, path: Line) -> Line {
// Just give up
path
}
fn snap_nodes_to_line(pts: &[Pt2D], pl: &PolyLine) -> Vec<Distance> {
let mut results = Vec::new();
for pt in pts {
let projected = pl.project_pt(*pt);
// TODO Check distance isn't too crazy? Not sure why it would be
if let Some((dist, _)) = pl.dist_along_of_point(projected) {
results.push(dist);
}
}
results
}

View File

@ -189,6 +189,9 @@ pub struct Road {
/// Meaningless order
pub transit_stops: BTreeSet<TransitStopID>,
/// Some kind of modal filter or barrier this distance along center_pts.
pub barrier_nodes: Vec<Distance>,
}
impl Road {

View File

@ -353,6 +353,11 @@ pub struct RawRoad {
/// Is there a tagged crosswalk near each end of the road?
pub crosswalk_forward: bool,
pub crosswalk_backward: bool,
/// Barrier nodes along this road's original center line.
// TODO Preserving these across transformations (especially merging dual carriageways!) could
// be really hard. It might be better to split the road into two pieces to match the more often
// used OSM style.
pub barrier_nodes: Vec<Pt2D>,
/// Derived from osm_tags. Not automatically updated.
pub lane_specs_ltr: Vec<LaneSpec>,
@ -376,6 +381,7 @@ impl RawRoad {
// later
crosswalk_forward: true,
crosswalk_backward: true,
barrier_nodes: Vec::new(),
lane_specs_ltr,
})