Iterate on the curb rendering for #715. A simple start to it already happens to exist for an old color scheme experiment.

Still some issues with shoulders, but improved in many cases.
This commit is contained in:
Dustin Carlino 2021-07-25 13:08:14 -07:00
parent 8eeee4cb8e
commit 835e4bf7a7
6 changed files with 90 additions and 46 deletions

View File

@ -195,6 +195,12 @@ impl ops::Mul<Distance> for f64 {
}
}
impl ops::MulAssign<f64> for Distance {
fn mul_assign(&mut self, other: f64) {
*self = *self * other;
}
}
impl ops::Div<Distance> for Distance {
type Output = f64;

View File

@ -408,6 +408,11 @@ impl PolyLine {
self.shift_left(width).unwrap()
}
/// Perpendicularly shifts the polyline to the right if positive or left if negative.
pub fn shift_either_direction(&self, width: Distance) -> Result<PolyLine> {
self.shift_with_corrections(width)
}
// Things to remember about shifting polylines:
// - the length before and after probably don't match up
// - the number of points may not match

View File

@ -71,6 +71,7 @@ pub struct ColorScheme {
pub sidewalk_lines: Option<Color>,
general_road_marking: Color,
road_center_line: Color,
pub curb: Color,
pub light_rail_track: Color,
pub private_road: Color,
unzoomed_highway: Color,
@ -197,6 +198,7 @@ impl ColorScheme {
sidewalk_lines: Some(Color::grey(0.7)),
general_road_marking: Color::WHITE,
road_center_line: Color::YELLOW,
curb: hex("#666666"),
light_rail_track: hex("#844204"),
private_road: hex("#F0B0C0"),
unzoomed_highway: hex("#E892A2"),

View File

@ -112,6 +112,7 @@ impl Options {
options.push(c.label.clone());
if c.label == x {
self.color_scheme = c.data;
self.toggle_day_night_colors = false;
ok = true;
break;
}

View File

@ -46,13 +46,12 @@ impl DrawIntersection {
},
i.polygon.clone(),
);
if app.cs().sidewalk_lines.is_some() {
default_geom.extend(
app.cs().zoomed_road_surface(LaneType::Sidewalk, rank),
calculate_corners(i, map),
);
} else {
calculate_corners_with_borders(&mut default_geom, app, i);
default_geom.extend(
app.cs().zoomed_road_surface(LaneType::Sidewalk, rank),
calculate_corners(i, map),
);
if app.cs().sidewalk_lines.is_none() {
default_geom.extend(app.cs().curb, calculate_corner_curbs(i, map));
}
for turn in map.get_turns_in_intersection(i.id) {
@ -279,40 +278,73 @@ pub fn calculate_corners(i: &Intersection, map: &Map) -> Vec<Polygon> {
corners
}
// calculate_corners smooths edges, but we don't want to do that when drawing explicit borders.
fn calculate_corners_with_borders(batch: &mut GeomBatch, app: &dyn AppLike, i: &Intersection) {
let map = app.map();
let rank = i.get_rank(map);
let surface_color = app.cs().zoomed_road_surface(LaneType::Sidewalk, rank);
let border_color = app.cs().general_road_marking(rank);
fn calculate_corner_curbs(i: &Intersection, map: &Map) -> Vec<Polygon> {
if i.is_footway(map) {
return Vec::new();
}
let mut curbs = Vec::new();
let thickness = Distance::meters(0.2);
let shift = |width| (width - thickness) / 2.0;
for turn in map.get_turns_in_intersection(i.id) {
if turn.turn_type != TurnType::SharedSidewalkCorner {
continue;
}
// Avoid double-rendering
if map.get_l(turn.id.src).dst_i != i.id {
continue;
}
let width = map
.get_l(turn.id.src)
.width
.min(map.get_l(turn.id.dst).width);
if turn.turn_type == TurnType::SharedSidewalkCorner {
// Avoid double-rendering
if map.get_l(turn.id.src).dst_i != i.id {
continue;
}
let l1 = map.get_l(turn.id.src);
let l2 = map.get_l(turn.id.dst);
// TODO This leaves gaps.
batch.push(surface_color, turn.geom.make_polygons(width));
// Special case for dead-ends: just thicken the geometry.
/*if i.roads.len() == 1 {
corners.push(turn.geom.make_polygons(l1.width.min(l2.width)));
continue;
}*/
let thickness = Distance::meters(0.2);
let shift = (width - thickness) / 2.0;
batch.push(
border_color,
turn.geom.must_shift_right(shift).make_polygons(thickness),
);
batch.push(
border_color,
turn.geom.must_shift_left(shift).make_polygons(thickness),
);
if l1.width == l2.width {
// When two sidewalks or two shoulders meet, use the turn geometry to create some
// nice rounding.
let mut width = shift(l1.width);
if map.get_config().driving_side == DrivingSide::Right {
width *= -1.0;
}
if let Some(pl) = (|| {
let mut pts = turn.geom.shift_either_direction(width).ok()?.into_points();
let first_line = l2.first_line().shift_either_direction(width);
pts.push(first_line.pt1());
pts.push(first_line.unbounded_dist_along(thickness));
let last_line = l1.last_line().shift_either_direction(width).reverse();
pts.insert(0, last_line.pt1());
pts.insert(0, last_line.unbounded_dist_along(thickness));
PolyLine::deduping_new(pts).ok()
})() {
curbs.push(pl.make_polygons(thickness));
}
} else {
// When a sidewalk and a shoulder meet, use a simpler shape to connect them.
let direction = if map.get_config().driving_side == DrivingSide::Right {
-1.0
} else {
1.0
};
if let Ok(pl) = PolyLine::new(vec![
l1.last_line()
.shift_either_direction(direction * shift(l1.width))
.pt2(),
l2.first_line()
.shift_either_direction(direction * shift(l2.width))
.pt1(),
]) {
curbs.push(pl.make_polygons(thickness));
}
}
}
}
curbs
}
// TODO This assumes the lanes change direction only at one point. A two-way cycletrack right at

View File

@ -48,19 +48,17 @@ impl DrawLane {
if let Some(c) = app.cs().sidewalk_lines {
batch.extend(c, calculate_sidewalk_lines(lane));
} else {
// Otherwise, draw a border at both edges
// Create a sense of depth at the curb
let width = Distance::meters(0.2);
let shift = (lane.width - width) / 2.0;
let mut shift = (lane.width - width) / 2.0;
if map.get_config().driving_side == DrivingSide::Right {
shift *= -1.0;
}
batch.push(
general_road_marking,
app.cs().curb,
lane.lane_center_pts
.must_shift_right(shift)
.make_polygons(width),
);
batch.push(
general_road_marking,
lane.lane_center_pts
.must_shift_left(shift)
.shift_either_direction(shift)
.unwrap()
.make_polygons(width),
);
}