Optionally import sidewalks and separate footpaths exactly as they're in OSM, instead of attempting any inference. This is a way to move forward on #161 without having to cutover to it all at once.

This commit is contained in:
Dustin Carlino 2020-10-30 13:27:45 -07:00
parent b1f4ca0b1b
commit bf0dce2c18
15 changed files with 61 additions and 43 deletions

View File

@ -9,8 +9,7 @@ use map_model::raw::{RawArea, RawBuilding, RawMap, RawParkingLot, RawRoad, Restr
use map_model::{osm, Amenity, AreaType, NamePerLanguage};
use crate::osm_geom::{get_multipolygon_members, glue_multipolygon, multipoly_geometry};
use crate::transit;
use crate::Options;
use crate::{transit, Options};
pub struct OsmExtract {
/// Unsplit roads
@ -409,6 +408,7 @@ fn is_road(tags: &mut Tags, opts: &Options) -> bool {
};
if !vec![
"footway",
"living_street",
"motorway",
"motorway_link",
@ -418,6 +418,7 @@ fn is_road(tags: &mut Tags, opts: &Options) -> bool {
"secondary",
"secondary_link",
"service",
"steps",
"tertiary",
"tertiary_link",
"trunk",
@ -429,6 +430,10 @@ fn is_road(tags: &mut Tags, opts: &Options) -> bool {
return false;
}
if (highway == "footway" || highway == "steps") && opts.map_config.inferred_sidewalks {
return false;
}
// Service roads can represent lots of things, most of which we don't want to keep yet. What's
// allowed here is just based on what's been encountered so far in Seattle and Kraków.
if highway == "service" {
@ -459,7 +464,7 @@ fn is_road(tags: &mut Tags, opts: &Options) -> bool {
// If there's no sidewalk data in OSM already, then make an assumption and mark that
// it's inferred.
if !tags.contains_key(osm::SIDEWALK) {
if !tags.contains_key(osm::SIDEWALK) && opts.map_config.inferred_sidewalks {
tags.insert(osm::INFERRED_SIDEWALKS, "true");
if tags.is_any(osm::HIGHWAY, vec!["motorway", "motorway_link"])
|| tags.is("junction", "roundabout")

View File

@ -41,7 +41,7 @@ pub fn snap_cycleways(map: &RawMap, timer: &mut Timer) {
if r.is_light_rail() || r.is_footway() || r.is_service() {
continue;
}
let (pl, total_width) = r.get_geometry(*id, map.config.driving_side);
let (pl, total_width) = r.get_geometry(*id, &map.config);
road_edges.insert(
(*id, Direction::Fwd),
pl.must_shift_right(total_width / 2.0),

View File

@ -72,6 +72,7 @@ pub fn osm_to_raw(name: &str, timer: &mut Timer, config: &ImporterConfiguration)
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::JustOSM,

View File

@ -31,6 +31,7 @@ pub fn osm_to_raw(name: &str, timer: &mut abstutil::Timer, config: &ImporterConf
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Right,
bikes_can_use_bus_lanes: false,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::SomeAdditionalWhereNoData { pct: 90 },

View File

@ -31,6 +31,7 @@ pub fn osm_to_raw(name: &str, timer: &mut abstutil::Timer, config: &ImporterConf
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Left,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::JustOSM,

View File

@ -225,6 +225,7 @@ fn oneshot(
map_model::DrivingSide::Left
},
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::JustOSM,

View File

@ -81,6 +81,7 @@ pub fn osm_to_raw(name: &str, timer: &mut abstutil::Timer, config: &ImporterConf
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::Blockface(abstutil::path(

View File

@ -31,6 +31,7 @@ pub fn osm_to_raw(name: &str, timer: &mut abstutil::Timer, config: &ImporterConf
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::SomeAdditionalWhereNoData { pct: 50 },

View File

@ -28,6 +28,7 @@ pub fn osm_to_raw(name: &str, timer: &mut abstutil::Timer, config: &ImporterConf
map_config: map_model::MapConfig {
driving_side: map_model::DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
onstreet_parking: convert_osm::OnstreetParking::JustOSM,

View File

@ -13,7 +13,7 @@ use geom::{Speed, Time};
use crate::make::initial::lane_specs::get_lane_specs_ltr;
use crate::{
connectivity, AccessRestrictions, BusRouteID, ControlStopSign, ControlTrafficSignal, Direction,
DrivingSide, IntersectionID, IntersectionType, LaneID, LaneType, Map, PathConstraints,
IntersectionID, IntersectionType, LaneID, LaneType, Map, MapConfig, PathConstraints,
Pathfinder, Road, RoadID, TurnID, Zone,
};
@ -61,9 +61,9 @@ pub struct EditRoad {
}
impl EditRoad {
pub fn get_orig_from_osm(r: &Road, driving_side: DrivingSide) -> EditRoad {
pub fn get_orig_from_osm(r: &Road, cfg: &MapConfig) -> EditRoad {
EditRoad {
lanes_ltr: get_lane_specs_ltr(&r.osm_tags, driving_side)
lanes_ltr: get_lane_specs_ltr(&r.osm_tags, cfg)
.into_iter()
.map(|spec| (spec.lt, spec.dir))
.collect(),
@ -194,8 +194,7 @@ impl MapEdits {
}
retain_btreeset(&mut self.changed_roads, |r| {
map.get_r_edit(*r)
!= EditRoad::get_orig_from_osm(map.get_r(*r), map.config.driving_side)
map.get_r_edit(*r) != EditRoad::get_orig_from_osm(map.get_r(*r), &map.config)
});
retain_btreemap(&mut self.original_intersections, |i, orig| {
map.get_i_edit(*i) != orig.clone()
@ -211,7 +210,7 @@ impl MapEdits {
for r in &self.changed_roads {
self.commands.push(EditCmd::ChangeRoad {
r: *r,
old: EditRoad::get_orig_from_osm(map.get_r(*r), map.config.driving_side),
old: EditRoad::get_orig_from_osm(map.get_r(*r), &map.config),
new: map.get_r_edit(*r),
});
}
@ -238,7 +237,7 @@ impl MapEdits {
let mut roads = BTreeSet::new();
for r in &self.changed_roads {
let r = map.get_r(*r);
let orig = EditRoad::get_orig_from_osm(r, map.get_config().driving_side);
let orig = EditRoad::get_orig_from_osm(r, map.get_config());
// What exactly changed?
if r.speed_limit != orig.speed_limit
|| r.access_restrictions != orig.access_restrictions

View File

@ -5,8 +5,8 @@ use abstutil::Tags;
use geom::Distance;
use crate::{
osm, Direction, DrivingSide, LaneType, NORMAL_LANE_THICKNESS, SERVICE_ROAD_LANE_THICKNESS,
SHOULDER_THICKNESS, SIDEWALK_THICKNESS,
osm, Direction, DrivingSide, LaneType, MapConfig, NORMAL_LANE_THICKNESS,
SERVICE_ROAD_LANE_THICKNESS, SHOULDER_THICKNESS, SIDEWALK_THICKNESS,
};
#[derive(PartialEq)]
@ -40,12 +40,12 @@ fn back(lt: LaneType) -> LaneSpec {
}
}
pub fn get_lane_specs_ltr(tags: &Tags, driving_side: DrivingSide) -> Vec<LaneSpec> {
pub fn get_lane_specs_ltr(tags: &Tags, cfg: &MapConfig) -> Vec<LaneSpec> {
// Easy special cases first.
if tags.is_any("railway", vec!["light_rail", "rail"]) {
return vec![fwd(LaneType::LightRail)];
}
if tags.is(osm::HIGHWAY, "footway") {
if tags.is_any(osm::HIGHWAY, vec!["footway", "pedestrian", "steps"]) {
return vec![fwd(LaneType::Sidewalk)];
}
@ -127,7 +127,7 @@ pub fn get_lane_specs_ltr(tags: &Tags, driving_side: DrivingSide) -> Vec<LaneSpe
}
if driving_lane == LaneType::Construction {
return assemble_ltr(fwd_side, back_side, driving_side);
return assemble_ltr(fwd_side, back_side, cfg.driving_side);
}
let fwd_bus_spec = if let Some(s) = tags.get("bus:lanes:forward") {
@ -228,13 +228,13 @@ pub fn get_lane_specs_ltr(tags: &Tags, driving_side: DrivingSide) -> Vec<LaneSpe
back_side.push(back(LaneType::Sidewalk));
}
} else if tags.is(osm::SIDEWALK, "right") {
if driving_side == DrivingSide::Right {
if cfg.driving_side == DrivingSide::Right {
fwd_side.push(fwd(LaneType::Sidewalk));
} else {
back_side.push(back(LaneType::Sidewalk));
}
} else if tags.is(osm::SIDEWALK, "left") {
if driving_side == DrivingSide::Right {
if cfg.driving_side == DrivingSide::Right {
back_side.push(back(LaneType::Sidewalk));
} else {
fwd_side.push(fwd(LaneType::Sidewalk));
@ -272,14 +272,16 @@ pub fn get_lane_specs_ltr(tags: &Tags, driving_side: DrivingSide) -> Vec<LaneSpe
need_back_shoulder = false;
}
if cfg.inferred_sidewalks {
if need_fwd_shoulder {
fwd_side.push(fwd(LaneType::Shoulder));
}
if need_back_shoulder {
back_side.push(back(LaneType::Shoulder));
}
}
assemble_ltr(fwd_side, back_side, driving_side)
assemble_ltr(fwd_side, back_side, cfg.driving_side)
}
fn assemble_ltr(
@ -428,7 +430,12 @@ mod tests {
"^^^",
),
] {
let actual = get_lane_specs_ltr(&tags(input.clone()), driving_side);
let cfg = MapConfig {
driving_side,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
};
let actual = get_lane_specs_ltr(&tags(input.clone()), &cfg);
let actual_lt = actual
.iter()
.map(|s| lt_to_char(s.lt))

View File

@ -10,7 +10,7 @@ use geom::{Bounds, Circle, Distance, PolyLine, Polygon, Pt2D};
pub use self::geometry::intersection_polygon;
use crate::raw::{OriginalRoad, RawMap, RawRoad};
use crate::{osm, DrivingSide, IntersectionType};
use crate::{osm, IntersectionType, MapConfig};
mod geometry;
pub mod lane_specs;
@ -35,9 +35,9 @@ pub struct Road {
}
impl Road {
pub fn new(id: OriginalRoad, r: &RawRoad, driving_side: DrivingSide) -> Road {
let lane_specs_ltr = lane_specs::get_lane_specs_ltr(&r.osm_tags, driving_side);
let (trimmed_center_pts, total_width) = r.get_geometry(id, driving_side);
pub fn new(id: OriginalRoad, r: &RawRoad, cfg: &MapConfig) -> Road {
let lane_specs_ltr = lane_specs::get_lane_specs_ltr(&r.osm_tags, cfg);
let (trimmed_center_pts, total_width) = r.get_geometry(id, cfg);
Road {
id,
@ -95,8 +95,7 @@ impl InitialMap {
m.intersections.get_mut(&id.i1).unwrap().roads.insert(*id);
m.intersections.get_mut(&id.i2).unwrap().roads.insert(*id);
m.roads
.insert(*id, Road::new(*id, r, raw.config.driving_side));
m.roads.insert(*id, Road::new(*id, r, &raw.config));
}
timer.start_iter("find each intersection polygon", m.intersections.len());

View File

@ -132,7 +132,8 @@ impl Map {
dst_i: i2,
speed_limit: Speed::ZERO,
zorder: if let Some(layer) = raw.roads[&r.id].osm_tags.get("layer") {
layer.parse::<isize>().unwrap()
// Just drop .5 for now
layer.parse::<f64>().unwrap() as isize
} else {
0
},

View File

@ -22,6 +22,10 @@ pub struct MapConfig {
/// (Australia).
pub driving_side: DrivingSide,
pub bikes_can_use_bus_lanes: bool,
/// If true, roads without explicitly tagged sidewalks may have sidewalks or shoulders. If
/// false, no sidewalks will be inferred if not tagged in OSM, and separate sidewalks will be
/// included.
pub inferred_sidewalks: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
@ -158,6 +162,7 @@ impl Map {
config: MapConfig {
driving_side: DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
pathfinder: Pathfinder::Dijkstra,
pathfinder_dirty: false,

View File

@ -102,6 +102,7 @@ impl RawMap {
config: MapConfig {
driving_side: DrivingSide::Right,
bikes_can_use_bus_lanes: true,
inferred_sidewalks: true,
},
}
}
@ -163,10 +164,7 @@ impl RawMap {
};
let mut roads = BTreeMap::new();
for r in &i.roads {
roads.insert(
*r,
initial::Road::new(*r, &self.roads[r], self.config.driving_side),
);
roads.insert(*r, initial::Road::new(*r, &self.roads[r], &self.config));
}
let (poly, debug) = initial::intersection_polygon(&i, &mut roads, timer).unwrap();
@ -262,12 +260,8 @@ pub struct RawRoad {
impl RawRoad {
/// Returns the corrected center and total width
pub fn get_geometry(
&self,
id: OriginalRoad,
driving_side: DrivingSide,
) -> (PolyLine, Distance) {
let lane_specs = get_lane_specs_ltr(&self.osm_tags, driving_side);
pub fn get_geometry(&self, id: OriginalRoad, cfg: &MapConfig) -> (PolyLine, Distance) {
let lane_specs = get_lane_specs_ltr(&self.osm_tags, cfg);
let mut total_width = Distance::ZERO;
let mut sidewalk_right = None;
let mut sidewalk_left = None;
@ -303,7 +297,8 @@ impl RawRoad {
}
pub fn is_footway(&self) -> bool {
self.osm_tags.is(osm::HIGHWAY, "pedestrian")
self.osm_tags
.is_any(osm::HIGHWAY, vec!["footway", "pedestrian", "steps"])
}
pub fn is_service(&self) -> bool {