Skip to content

Commit

Permalink
Import footways and shared-use paths! The analogue to
Browse files Browse the repository at this point in the history
a-b-street/osm2streets#90.

Also remove the pedestrian plaza area type for now. It adds visual
clutter and has no editing/simulation/semantic impact yet.
  • Loading branch information
dabreegster committed Sep 15, 2022
1 parent a791a5c commit 8c5778e
Show file tree
Hide file tree
Showing 14 changed files with 91 additions and 44 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ http-range-client = { git = "https://github.com/pka/http-range-client", rev = "e

# To temporarily work on dependencies locally, uncomment this
# TODO Do not commit. Update each repo
#[patch."https://github.com/a-b-street/osm2streets"]
#import_streets = { path = "/home/dabreegster/osm2streets/import_streets" }
#street_network = { path = "/home/dabreegster/osm2streets/street_network" }
[patch."https://github.com/a-b-street/osm2streets"]
import_streets = { path = "/home/dabreegster/osm2streets/import_streets" }
street_network = { path = "/home/dabreegster/osm2streets/street_network" }
3 changes: 2 additions & 1 deletion apps/game/src/edit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,8 @@ pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {

pub fn can_edit_lane(app: &App, l: LaneID) -> bool {
let map = &app.primary.map;
if map.get_l(l).is_light_rail() {
let lane = map.get_l(l);
if lane.is_light_rail() || lane.is_footway() {
return false;
}
let r = map.get_parent(l);
Expand Down
2 changes: 1 addition & 1 deletion apps/game/src/edit/roads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ fn lane_type_to_icon(lt: LaneType) -> Option<&'static str> {
}
LaneType::Buffer(BufferType::Curb) => Some("system/assets/edit/buffer/curb.svg"),
// Don't allow creating these yet
LaneType::LightRail => None,
LaneType::LightRail | LaneType::Footway | LaneType::SharedUse => None,
}
}

Expand Down
4 changes: 0 additions & 4 deletions convert_osm/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,10 +312,6 @@ fn get_area_type(tags: &Tags) -> Option<AreaType> {
return Some(AreaType::Island);
}

if tags.is(osm::HIGHWAY, "pedestrian") {
return Some(AreaType::PedestrianPlaza);
}

None
}

Expand Down
35 changes: 21 additions & 14 deletions map_gui/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ pub struct ColorScheme {
pub unzoomed_highway: Color,
pub unzoomed_arterial: Color,
pub unzoomed_residential: Color,
pub unzoomed_trail: Color,
pub unzoomed_cycleway: Color,
pub unzoomed_footway: Color,
footway: Color,
shared_use: Color,

// Intersections
pub normal_intersection: Color,
Expand Down Expand Up @@ -123,8 +126,6 @@ pub struct ColorScheme {
pub parking_lot: Color,
pub grass: Fill,
pub water: Fill,
pub median_strip: Fill,
pub pedestrian_plaza: Fill,
pub study_area: Fill,

// Unzoomed dynamic elements
Expand Down Expand Up @@ -218,7 +219,11 @@ impl ColorScheme {
unzoomed_highway: hex("#E892A2"),
unzoomed_arterial: hex("#FFC73E"),
unzoomed_residential: Color::WHITE,
unzoomed_trail: hex("#0F7D4B"),
unzoomed_cycleway: hex("#0F7D4B"),
unzoomed_footway: hex("#DED68A"),
// TODO Distinguish shared use and footway unzoomed or zoomed?
footway: hex("#DED68A"),
shared_use: hex("#DED68A"),

// Intersections
normal_intersection: Color::grey(0.2),
Expand Down Expand Up @@ -246,8 +251,6 @@ impl ColorScheme {
parking_lot: Color::grey(0.7),
grass: hex("#94C84A").into(),
water: hex("#A4C8EA").into(),
median_strip: Color::CYAN.into(),
pedestrian_plaza: hex("#DDDDE8").into(),
study_area: hex("#96830C").into(),

// Unzoomed dynamic elements
Expand Down Expand Up @@ -319,7 +322,6 @@ impl ColorScheme {
cs.unzoomed_interesting_intersection = cs.unzoomed_highway;
cs.stop_sign = hex("#A32015");
cs.private_road = Some(hex("#9E757F"));
cs.pedestrian_plaza = hex("#94949C").into();
cs.study_area = hex("#D9B002").into();

cs.panel_bg = cs.gui_style.panel_bg;
Expand Down Expand Up @@ -376,7 +378,8 @@ impl ColorScheme {
cs.unzoomed_highway = Color::WHITE;
cs.unzoomed_arterial = Color::WHITE;
cs.unzoomed_residential = Color::WHITE;
cs.unzoomed_trail = Color::CLEAR;
cs.unzoomed_cycleway = Color::CLEAR;
cs.unzoomed_footway = Color::CLEAR;
cs.light_rail_track = Color::CLEAR;

// The colors of cells will show through these, de-emphasizing them
Expand Down Expand Up @@ -443,6 +446,8 @@ impl ColorScheme {
LaneType::Construction => parking_asphalt,
LaneType::LightRail => unreachable!(),
LaneType::Buffer(_) => main_asphalt,
LaneType::Footway => self.footway,
LaneType::SharedUse => self.shared_use,
}
}
pub fn zoomed_intersection_surface(&self, rank: RoadRank) -> Color {
Expand Down Expand Up @@ -483,7 +488,8 @@ impl ColorScheme {
"unzoomed_residential {}",
self.unzoomed_residential.as_hex()
)?;
writeln!(f, "unzoomed_trail {}", self.unzoomed_trail.as_hex())?;
writeln!(f, "unzoomed_cycleway {}", self.unzoomed_cycleway.as_hex())?;
writeln!(f, "unzoomed_footway {}", self.unzoomed_footway.as_hex())?;
writeln!(
f,
"residential_building {}",
Expand Down Expand Up @@ -518,11 +524,12 @@ impl ColorScheme {
self.unzoomed_highway = colors[0];
self.unzoomed_arterial = colors[1];
self.unzoomed_residential = colors[2];
self.unzoomed_trail = colors[3];
self.residential_building = colors[4];
self.commercial_building = colors[5];
self.grass = Fill::Color(colors[6]);
self.water = Fill::Color(colors[7]);
self.unzoomed_cycleway = colors[3];
self.unzoomed_footway = colors[4];
self.residential_building = colors[5];
self.commercial_building = colors[6];
self.grass = Fill::Color(colors[7]);
self.water = Fill::Color(colors[8]);

Ok(())
}
Expand Down
2 changes: 0 additions & 2 deletions map_gui/src/render/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ impl DrawArea {
AreaType::Park => cs.grass.clone(),
AreaType::Water => cs.water.clone(),
AreaType::Island => cs.map_background.clone(),
AreaType::MedianStrip => cs.median_strip.clone(),
AreaType::PedestrianPlaza => cs.pedestrian_plaza.clone(),
AreaType::StudyArea => cs.study_area.clone(),
}
}
Expand Down
23 changes: 19 additions & 4 deletions map_gui/src/render/intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ impl DrawIntersection {
let rank = i.get_rank(map);
default_geom.push(
if i.is_footway(map) {
app.cs().zoomed_road_surface(LaneType::Sidewalk, rank)
// TODO Or maybe shared-use, once there's some visual distinction there
app.cs().zoomed_road_surface(LaneType::Footway, rank)
} else if i.is_cycleway(map) {
app.cs().zoomed_road_surface(LaneType::Biking, rank)
} else {
Expand All @@ -56,6 +57,18 @@ impl DrawIntersection {
if app.cs().road_outlines {
default_geom.extend(app.cs().curb(rank), calculate_corner_curbs(i, map));
}
if i.is_footway(map) {
for pl in Self::get_unzoomed_outline(i, map) {
default_geom.extend(
Color::BLACK,
pl.exact_dashed_polygons(
Distance::meters(0.25),
Distance::meters(1.0),
Distance::meters(1.5),
),
);
}
}

for turn in &i.turns {
if !app.opts().show_crosswalks {
Expand Down Expand Up @@ -290,9 +303,10 @@ impl Renderable for DrawIntersection {
}
}

// TODO Temporarily public for debugging.
// Public for debugging
pub fn calculate_corners(i: &Intersection, map: &Map) -> Vec<Polygon> {
if i.is_footway(map) {
// Don't attempt corners for footways or where normal roads and footways meet
if i.roads.iter().any(|r| map.get_r(*r).is_footway()) {
return Vec::new();
}

Expand Down Expand Up @@ -372,7 +386,8 @@ pub fn calculate_corners(i: &Intersection, map: &Map) -> Vec<Polygon> {
}

fn calculate_corner_curbs(i: &Intersection, map: &Map) -> Vec<Polygon> {
if i.is_footway(map) {
// Don't attempt corners for footways or where normal roads and footways meet
if i.roads.iter().any(|r| map.get_r(*r).is_footway()) {
return Vec::new();
}

Expand Down
19 changes: 18 additions & 1 deletion map_gui/src/render/lane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl DrawLane {
if lane.is_sidewalk() {
batch.extend(app.cs().sidewalk_lines, calculate_sidewalk_lines(lane));
}
if app.cs().road_outlines && !road.is_footway() {
if app.cs().road_outlines {
// Create a sense of depth at the curb
let width = Distance::meters(0.2);
let mut shift = (lane.width - width) / 2.0;
Expand Down Expand Up @@ -174,6 +174,23 @@ impl DrawLane {
LaneType::Buffer(style) => {
calculate_buffer_markings(app, style, lane, &mut batch);
}
LaneType::Footway | LaneType::SharedUse => {
// Dashed lines on both sides
for dir in [-1.0, 1.0] {
let pl = lane
.lane_center_pts
.shift_either_direction(dir * lane.width / 2.0)
.unwrap();
batch.extend(
Color::BLACK,
pl.exact_dashed_polygons(
Distance::meters(0.25),
Distance::meters(1.0),
Distance::meters(1.5),
),
);
}
}
}

if road.is_private() {
Expand Down
17 changes: 12 additions & 5 deletions map_gui/src/render/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ impl DrawMap {
Fill::Color(if r.is_light_rail() {
cs.light_rail_track
} else if r.is_cycleway() {
cs.unzoomed_trail
cs.unzoomed_cycleway
} else if r.is_footway() {
cs.unzoomed_footway
} else if r.is_private() && cs.private_road.is_some() {
cs.private_road.unwrap()
} else {
Expand All @@ -252,9 +254,9 @@ impl DrawMap {
.into_iter()
.flatten()
{
if opts.simplify_basemap && r.is_cycleway() {
if (opts.simplify_basemap && r.is_cycleway()) || r.is_footway() {
for p in pl.exact_dashed_polygons(
outline_thickness,
0.5 * outline_thickness,
Distance::meters(5.0),
Distance::meters(2.0),
) {
Expand Down Expand Up @@ -291,7 +293,9 @@ impl DrawMap {
if i.is_light_rail(map) {
cs.light_rail_track
} else if i.is_cycleway(map) {
cs.unzoomed_trail
cs.unzoomed_cycleway
} else if i.is_footway(map) {
cs.unzoomed_footway
} else if i.is_private(map) && cs.private_road.is_some() {
cs.private_road.unwrap()
} else {
Expand All @@ -303,11 +307,14 @@ impl DrawMap {
unzoomed_pieces.push((zorder, intersection_color.into(), i.polygon.clone().into()));

if cs.road_outlines {
// It'd be nice to dash the outline for footways, but usually the pieces of the
// outline in between the roads are too small to dash, and using the entire thing
// would look like the intersection is blocked off
for pl in DrawIntersection::get_unzoomed_outline(i, map) {
unzoomed_pieces.push((
zorder + outline_z_offset,
outline_color.into(),
pl.make_polygons(outline_thickness).into(),
pl.make_polygons(0.5 * outline_thickness).into(),
));
}
}
Expand Down
5 changes: 5 additions & 0 deletions map_model/src/objects/lane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ impl Lane {
self.lane_type == LaneType::LightRail
}

// TODO Misleading?
pub fn is_footway(&self) -> bool {
self.lane_type == LaneType::Footway || self.lane_type == LaneType::SharedUse
}

pub fn get_directed_parent(&self) -> DirectedRoadID {
DirectedRoadID {
road: self.id.road,
Expand Down
7 changes: 5 additions & 2 deletions map_model/src/objects/road.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,14 +422,17 @@ impl Road {
}

pub fn is_footway(&self) -> bool {
self.lanes.len() == 1 && self.lanes[0].lane_type == LaneType::Sidewalk
self.lanes.len() == 1
&& matches!(
self.lanes[0].lane_type,
LaneType::Footway | LaneType::SharedUse
)
}

pub fn is_service(&self) -> bool {
self.osm_tags.is(osm::HIGHWAY, "service")
}

// TODO Shared walking/biking roads get classified as a cycleway for now
pub fn is_cycleway(&self) -> bool {
let mut bike = false;
for lane in &self.lanes {
Expand Down
7 changes: 5 additions & 2 deletions map_model/src/pathfind/uber_turns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use serde::{Deserialize, Serialize};

use geom::{Distance, PolyLine};

use crate::{DirectedRoadID, IntersectionID, LaneID, Map, MovementID, TurnID};
use crate::{DirectedRoadID, IntersectionID, LaneID, Map, MovementID, PathConstraints, TurnID};

/// This only applies to VehiclePathfinder; walking through these intersections is nothing special.
/// And in fact, even lanes only for buses/bikes are ignored.
// TODO I haven't seen any cases yet with "interior" intersections. Some stuff might break.
pub struct IntersectionCluster {
pub members: BTreeSet<IntersectionID>,
Expand Down Expand Up @@ -200,7 +201,9 @@ fn flood(start: TurnID, map: &Map, exits: &BTreeSet<TurnID>) -> Vec<UberTurn> {

while !queue.is_empty() {
let current = queue.pop().unwrap();
for next in map.get_turns_from_lane(current.dst) {
// Filtering for car lanes is necessary near https://www.openstreetmap.org/node/1283661439,
// where there's a bidirectional shared-use path
for next in map.get_turns_for(current.dst, PathConstraints::Car) {
if preds.contains_key(&next.id) {
continue;
}
Expand Down
3 changes: 0 additions & 3 deletions raw_map/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,6 @@ pub enum AreaType {
Park,
Water,
Island,
// TODO This is unused, could delete. It'll change the binary format, so no urgency.
MedianStrip,
PedestrianPlaza,
/// Not from OSM. A user-specified area to focus on.
StudyArea,
}

0 comments on commit 8c5778e

Please sign in to comment.