Skip to content

Commit

Permalink
Create new lane types to express different types of buffers for prote… (
Browse files Browse the repository at this point in the history
#704)

* Create new lane types to express different types of buffers for protected bike lanes. They're only created manually right now, to explore rendering.

* Update planter rendering

* Update planter - simplify

* fmt after merge

* Fixing up existing rendering

* Add curb buffer

* Adjust stripes

Co-authored-by: Robin Lovelace <[email protected]>
  • Loading branch information
dabreegster and Robinlovelace authored Jul 23, 2021
1 parent 1d7c8ce commit b45f9e0
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 12 deletions.
4 changes: 4 additions & 0 deletions data/system/assets/edit/buffer/curb.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions data/system/assets/edit/buffer/flex_posts.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions data/system/assets/edit/buffer/jersey_barrier.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions data/system/assets/edit/buffer/planters.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions data/system/assets/edit/buffer/stripes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions game/src/debug/shared_row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ fn lane(lane: &Lane) -> Option<serde_json::Map<String, serde_json::value::Value>
LaneType::LightRail => {
return None;
}
// TODO
LaneType::Buffer(_) => {
return None;
}
},
);
if lane.lane_type == LaneType::SharedLeftTurn {
Expand Down
1 change: 1 addition & 0 deletions game/src/debug/streetmix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ fn lane(lane: &Lane, dir: Direction) -> serde_json::Map<String, serde_json::valu
LaneType::SharedLeftTurn => ("TODO", "TODO"),
LaneType::Construction => ("TODO", "TODO"),
LaneType::LightRail => ("TODO", "TODO"),
LaneType::Buffer(_) => ("TODO", "TODO"),
};
segment.insert("type".to_string(), segment_type.into());
segment.insert("variant".to_string(), variant.into());
Expand Down
36 changes: 28 additions & 8 deletions game/src/edit/roads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use map_gui::render::{Renderable, OUTLINE_THICKNESS};
use map_gui::tools::PopupMsg;
use map_gui::ID;
use map_model::{
Direction, EditCmd, EditRoad, LaneID, LaneSpec, LaneType, MapEdits, Road, RoadID,
BufferType, Direction, EditCmd, EditRoad, LaneID, LaneSpec, LaneType, MapEdits, Road, RoadID,
NORMAL_LANE_THICKNESS,
};
use widgetry::{
Expand Down Expand Up @@ -464,12 +464,17 @@ fn make_main_panel(

let current_lts: Vec<LaneType> = road.lanes_ltr().into_iter().map(|(_, _, lt)| lt).collect();
let mut available_lane_types_row = vec![
(LaneType::Driving, Key::D),
(LaneType::Biking, Key::B),
(LaneType::Bus, Key::T),
(LaneType::Parking, Key::P),
(LaneType::Construction, Key::C),
(LaneType::Sidewalk, Key::S),
(LaneType::Driving, Some(Key::D)),
(LaneType::Biking, Some(Key::B)),
(LaneType::Bus, Some(Key::T)),
(LaneType::Parking, Some(Key::P)),
(LaneType::Construction, Some(Key::C)),
(LaneType::Sidewalk, Some(Key::S)),
(LaneType::Buffer(BufferType::Stripes), None),
(LaneType::Buffer(BufferType::FlexPosts), None),
(LaneType::Buffer(BufferType::Planters), None),
(LaneType::Buffer(BufferType::JerseyBarrier), None),
(LaneType::Buffer(BufferType::Curb), None),
]
.into_iter()
.map(|(lt, key)| {
Expand All @@ -478,7 +483,7 @@ fn make_main_panel(
.btn_plain
.icon(lane_type_to_icon(lt).unwrap())
.hotkey(if current_lane.is_some() {
Some(key.into())
key.map(|k| k.into())
} else {
None
});
Expand Down Expand Up @@ -674,6 +679,13 @@ fn lane_type_to_icon(lt: LaneType) -> Option<&'static str> {
LaneType::Bus => Some("system/assets/edit/bus.svg"),
LaneType::SharedLeftTurn => Some("system/assets/map/shared_left_turn.svg"),
LaneType::Construction => Some("system/assets/edit/construction.svg"),
LaneType::Buffer(BufferType::Stripes) => Some("system/assets/edit/buffer/stripes.svg"),
LaneType::Buffer(BufferType::FlexPosts) => Some("system/assets/edit/buffer/flex_posts.svg"),
LaneType::Buffer(BufferType::Planters) => Some("system/assets/edit/buffer/planters.svg"),
LaneType::Buffer(BufferType::JerseyBarrier) => {
Some("system/assets/edit/buffer/jersey_barrier.svg")
}
LaneType::Buffer(BufferType::Curb) => Some("system/assets/edit/buffer/curb.svg"),
// Don't allow creating these yet
LaneType::LightRail => None,
}
Expand Down Expand Up @@ -769,6 +781,10 @@ fn add_new_lane(road: &mut EditRoad, lt: LaneType) -> usize {
road.lanes_ltr.last().unwrap().dir
}
}
LaneType::Buffer(_) => {
// TODO Look for the bike lane that's missing a buffer
Direction::Fwd
}
_ => unreachable!(),
};

Expand All @@ -792,6 +808,10 @@ fn add_new_lane(road: &mut EditRoad, lt: LaneType) -> usize {
road.lanes_ltr.len()
}
}
LaneType::Buffer(_) => {
// TODO Look for the bike lane that's missing a buffer
0
}
_ => unreachable!(),
};

Expand Down
1 change: 1 addition & 0 deletions map_gui/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ impl ColorScheme {
LaneType::SharedLeftTurn => self.driving_lane,
LaneType::Construction => self.parking_lane,
LaneType::LightRail => unreachable!(),
LaneType::Buffer(_) => self.driving_lane,
},
}
}
Expand Down
104 changes: 101 additions & 3 deletions map_gui/src/render/lane.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::cell::RefCell;
use std::collections::HashMap;

use geom::{Angle, ArrowCap, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Direction, DrivingSide, Lane, LaneID, LaneType, Map, Road, RoadID, TurnID};
use widgetry::{Drawable, GeomBatch, GfxCtx, Prerender, RewriteColor};
use geom::{Angle, ArrowCap, Circle, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{
BufferType, Direction, DrivingSide, Lane, LaneID, LaneType, Map, Road, RoadID, TurnID,
};
use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Prerender, RewriteColor};

use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
use crate::{AppLike, ID};
Expand Down Expand Up @@ -172,6 +174,9 @@ impl DrawLane {
);
}
}
LaneType::Buffer(style) => {
calculate_buffer_markings(app, style, lane, road, &mut batch);
}
}

if road.is_private() {
Expand Down Expand Up @@ -384,3 +389,96 @@ fn calculate_one_way_markings(lane: &Lane, parent: &Road) -> Vec<Polygon> {
}
results
}

fn calculate_buffer_markings(
app: &dyn AppLike,
style: BufferType,
lane: &Lane,
road: &Road,
batch: &mut GeomBatch,
) {
let color = app.cs().general_road_marking(road.get_rank());

let side_lines = |batch: &mut GeomBatch| {
let thickness = Distance::meters(0.25);
batch.push(
color,
lane.lane_center_pts
.must_shift_right((lane.width - thickness) / 2.0)
.make_polygons(thickness),
);
batch.push(
color,
lane.lane_center_pts
.must_shift_left((lane.width - thickness) / 2.0)
.make_polygons(thickness),
);
};

let stripes = |batch: &mut GeomBatch, step_size, buffer_ends| {
for (center, angle) in lane.lane_center_pts.step_along(step_size, buffer_ends) {
// Extend the stripes into the side lines
let thickness = Distance::meters(0.25);
let left = center.project_away(lane.width / 2.0 + thickness, angle.rotate_degs(45.0));
let right = center.project_away(
lane.width / 2.0 + thickness,
angle.rotate_degs(45.0).opposite(),
);
batch.push(
color,
Line::must_new(left, right).make_polygons(Distance::meters(0.3)),
);
}
};

let dark_grey = Color::grey(0.6);
let light_grey = Color::grey(0.8);
match style {
BufferType::Stripes => {
side_lines(batch);
stripes(batch, Distance::meters(3.0), Distance::meters(5.0));
}
BufferType::FlexPosts => {
side_lines(batch);
stripes(batch, Distance::meters(3.0), Distance::meters(2.5));
for (pt, _) in lane
.lane_center_pts
.step_along(Distance::meters(3.0), Distance::meters(2.5 + 1.5))
{
let circle = Circle::new(pt, 0.3 * lane.width);
batch.push(light_grey, circle.to_polygon());
if let Ok(poly) = circle.to_outline(Distance::meters(0.25)) {
batch.push(dark_grey, poly);
}
}
}
BufferType::Planters => {
side_lines(batch);
// TODO Center the planters between the stripes
stripes(batch, Distance::meters(3.0), Distance::meters(5.0));
for poly in lane.lane_center_pts.dashed_lines(
0.6 * lane.width,
Distance::meters(2.0),
Distance::meters(2.5),
) {
batch.push(Color::hex("#108833"), poly.clone());
if let Ok(border) = poly.to_outline(Distance::meters(0.25)) {
batch.push(Color::hex("#A8882A"), border);
}
}
}
BufferType::JerseyBarrier => {
let buffer_ends = Distance::meters(2.0);
if let Ok(pl) = lane
.lane_center_pts
.maybe_exact_slice(buffer_ends, lane.lane_center_pts.length() - buffer_ends)
{
batch.push(dark_grey, pl.make_polygons(0.8 * lane.width));
batch.push(light_grey, pl.make_polygons(0.5 * lane.width));
}
}
BufferType::Curb => {
batch.push(dark_grey, lane.lane_center_pts.make_polygons(lane.width));
}
}
}
2 changes: 1 addition & 1 deletion map_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub use crate::objects::building::{
pub use crate::objects::bus_stop::{BusRoute, BusRouteID, BusStop, BusStopID};
pub use crate::objects::intersection::{Intersection, IntersectionID, IntersectionType};
pub use crate::objects::lane::{
Lane, LaneID, LaneSpec, LaneType, NORMAL_LANE_THICKNESS, PARKING_LOT_SPOT_LENGTH,
BufferType, Lane, LaneID, LaneSpec, LaneType, NORMAL_LANE_THICKNESS, PARKING_LOT_SPOT_LENGTH,
SIDEWALK_THICKNESS,
};
pub use crate::objects::parking_lot::{ParkingLot, ParkingLotID};
Expand Down
44 changes: 44 additions & 0 deletions map_model/src/objects/lane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ pub enum LaneType {
SharedLeftTurn,
Construction,
LightRail,
Buffer(BufferType),
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BufferType {
/// Just paint!
Stripes,
/// Flex posts, wands, cones, other "weak" forms of protection. Can weave through them.
FlexPosts,
/// Sturdier planters, with gaps.
Planters,
/// Solid barrier, no gaps.
JerseyBarrier,
/// A raised curb
Curb,
}

impl LaneType {
Expand All @@ -62,6 +77,7 @@ impl LaneType {
LaneType::SharedLeftTurn => false,
LaneType::Construction => false,
LaneType::LightRail => true,
LaneType::Buffer(_) => false,
}
}

Expand All @@ -76,6 +92,7 @@ impl LaneType {
LaneType::SharedLeftTurn => false,
LaneType::Construction => false,
LaneType::LightRail => true,
LaneType::Buffer(_) => false,
}
}

Expand All @@ -94,6 +111,11 @@ impl LaneType {
LaneType::SharedLeftTurn => "a shared left-turn lane",
LaneType::Construction => "a lane that's closed for construction",
LaneType::LightRail => "a light rail track",
LaneType::Buffer(BufferType::Stripes) => "striped pavement",
LaneType::Buffer(BufferType::FlexPosts) => "flex post barriers",
LaneType::Buffer(BufferType::Planters) => "planter barriers",
LaneType::Buffer(BufferType::JerseyBarrier) => "a Jersey barrier",
LaneType::Buffer(BufferType::Curb) => "a raised curb",
}
}

Expand All @@ -108,6 +130,11 @@ impl LaneType {
LaneType::SharedLeftTurn => "left-turn lane",
LaneType::Construction => "construction",
LaneType::LightRail => "light rail track",
LaneType::Buffer(BufferType::Stripes) => "stripes",
LaneType::Buffer(BufferType::FlexPosts) => "flex posts",
LaneType::Buffer(BufferType::Planters) => "planters",
LaneType::Buffer(BufferType::JerseyBarrier) => "Jersey barrier",
LaneType::Buffer(BufferType::Curb) => "curb",
}
}

Expand All @@ -122,6 +149,11 @@ impl LaneType {
"left-turn lane" => Some(LaneType::SharedLeftTurn),
"construction" => Some(LaneType::Construction),
"light rail track" => Some(LaneType::LightRail),
"stripes" => Some(LaneType::Buffer(BufferType::Stripes)),
"flex posts" => Some(LaneType::Buffer(BufferType::FlexPosts)),
"planters" => Some(LaneType::Buffer(BufferType::Planters)),
"Jersey barrier" => Some(LaneType::Buffer(BufferType::JerseyBarrier)),
"curb" => Some(LaneType::Buffer(BufferType::Curb)),
_ => None,
}
}
Expand Down Expand Up @@ -454,6 +486,18 @@ impl LaneSpec {
(Distance::feet(6.0), "wide"),
],
LaneType::Shoulder => vec![(SHOULDER_THICKNESS, "default")],
// Pretty wild guesses
LaneType::Buffer(BufferType::Stripes) => vec![(Distance::meters(1.5), "default")],
LaneType::Buffer(BufferType::FlexPosts) => {
vec![(Distance::meters(1.5), "default")]
}
LaneType::Buffer(BufferType::Planters) => {
vec![(Distance::meters(2.0), "default")]
}
LaneType::Buffer(BufferType::JerseyBarrier) => {
vec![(Distance::meters(1.5), "default")]
}
LaneType::Buffer(BufferType::Curb) => vec![(Distance::meters(0.5), "default")],
}
}
}
Expand Down

0 comments on commit b45f9e0

Please sign in to comment.