Fixes issue #173 Part B (#917)

* Fixes issue #173 Part B

This commit changes the color of road labels to white, and adds a black
stroke. It also removes center line dashes from the beginning of the
road label to the end.

* cargo fmt and fix syntax warnings

* Adds changes from PR #917 Review

This commit adds the changes requested in PR #917.

* Rebase and cargo fmt

* A few cleanups:

- make render_center_line private
- make usage of the 0.1 factor more clear
- work in Distance::meters

* Disable the curvey label experiment before merging, but now we don't
need to draw the background for non-curvey labels either!

* Draw the full center-line when appropriate

* Screenshot diff

Co-authored-by: Dustin Carlino <dabreegster@gmail.com>
This commit is contained in:
James Nebeker 2022-05-24 07:55:23 -06:00 committed by GitHub
parent 8f49dddaee
commit ee7f843ff6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 136 additions and 97 deletions

View File

@ -1441,9 +1441,9 @@
"compressed_size_bytes": 3896689
},
"data/input/gb/london/screenshots/kennington.zip": {
"checksum": "1f023c54a925f4d54afb2a9a3a74ecea",
"uncompressed_size_bytes": 6674339,
"compressed_size_bytes": 6673167
"checksum": "19abb1d8c10ca063901ab9c876e5eca6",
"uncompressed_size_bytes": 6600386,
"compressed_size_bytes": 6599250
},
"data/input/gb/long_marston/osm/center.osm": {
"checksum": "c7c25ca197870b843ac79c591c1275f3",
@ -2091,9 +2091,9 @@
"compressed_size_bytes": 3215418
},
"data/input/pl/krakow/screenshots/center.zip": {
"checksum": "ff5f39a48d7f6ea1943e2abd5569937f",
"uncompressed_size_bytes": 37103479,
"compressed_size_bytes": 37099988
"checksum": "c5927c5639d035c02f9f075fdcc2fa54",
"uncompressed_size_bytes": 36713667,
"compressed_size_bytes": 36710148
},
"data/input/pl/warsaw/osm/center.osm": {
"checksum": "b41830dd375674ffc9f7ec15d6cf9c0c",
@ -2731,9 +2731,9 @@
"compressed_size_bytes": 384258
},
"data/input/us/phoenix/screenshots/tempe.zip": {
"checksum": "32665a738ab6e43098feae621a4873b8",
"uncompressed_size_bytes": 10152381,
"compressed_size_bytes": 10150625
"checksum": "cbf1aae43c64bb83a630a7ea16e54127",
"uncompressed_size_bytes": 10088176,
"compressed_size_bytes": 10086412
},
"data/input/us/providence/osm/downtown.osm": {
"checksum": "463b986adc83ae4d1174496a4ce744d1",
@ -3081,14 +3081,14 @@
"compressed_size_bytes": 4992247
},
"data/input/us/seattle/screenshots/downtown.zip": {
"checksum": "1713164bc2544478f58a9e0dcc799481",
"uncompressed_size_bytes": 28777110,
"compressed_size_bytes": 28769092
"checksum": "45bd51e7ac9c59e73ff65acbd0dfcf18",
"uncompressed_size_bytes": 28343657,
"compressed_size_bytes": 28336193
},
"data/input/us/seattle/screenshots/montlake.zip": {
"checksum": "486a02377c86064a584c60cc8939c47f",
"uncompressed_size_bytes": 5455080,
"compressed_size_bytes": 5455031
"checksum": "d0c79530e0ad648bf83f13549448015e",
"uncompressed_size_bytes": 5402505,
"compressed_size_bytes": 5402436
},
"data/input/us/seattle/trips_2014.csv": {
"checksum": "d4a8e733045b28c0385fb81359d6df03",

View File

@ -10,6 +10,12 @@ use crate::render::lane::DrawLane;
use crate::render::{DrawOptions, Renderable};
use crate::{AppLike, ID};
// The default font size is too large; shrink it down to fit on roads better.
const LABEL_SCALE_FACTOR: f64 = 0.1;
// Making the label follow the road's curvature usually looks better, but sometimes the letters
// squish together, so keep this experiment disabled for now.
const DRAW_CURVEY_LABEL: bool = false;
pub struct DrawRoad {
pub id: RoadID,
zorder: isize,
@ -28,95 +34,57 @@ impl DrawRoad {
}
}
pub fn render_center_line(&self, app: &dyn AppLike) -> GeomBatch {
let r = app.map().get_r(self.id);
let center_line_color = if r.is_private() && app.cs().private_road.is_some() {
app.cs()
.road_center_line
.lerp(app.cs().private_road.unwrap(), 0.5)
} else {
app.cs().road_center_line
};
let mut batch = GeomBatch::new();
// Draw a center line every time two driving/bike/bus lanes of opposite direction are
// adjacent.
let mut width = Distance::ZERO;
for pair in r.lanes.windows(2) {
width += pair[0].width;
if pair[0].dir != pair[1].dir
&& pair[0].lane_type.is_for_moving_vehicles()
&& pair[1].lane_type.is_for_moving_vehicles()
{
let pl = r.shift_from_left_side(width).unwrap();
batch.extend(
center_line_color,
pl.dashed_lines(
Distance::meters(0.25),
Distance::meters(2.0),
Distance::meters(1.0),
),
);
}
}
batch
}
pub fn render<P: AsRef<Prerender>>(&self, prerender: &P, app: &dyn AppLike) -> GeomBatch {
let prerender = prerender.as_ref();
let r = app.map().get_r(self.id);
let center_line_color = if r.is_private() && app.cs().private_road.is_some() {
app.cs()
.road_center_line
.lerp(app.cs().private_road.unwrap(), 0.5)
} else {
app.cs().road_center_line
};
let mut batch = self.render_center_line(app);
if r.is_light_rail() {
// No label or center-line
return GeomBatch::new();
}
let name = r.get_name(app.opts().language.as_ref());
let mut batch;
if r.length() >= Distance::meters(30.0) && name != "???" {
// Render a label, so split the center-line into two pieces
let text_width =
Distance::meters(Text::from(&name).rendered_width(prerender) * LABEL_SCALE_FACTOR);
batch = render_center_line(app, r, Some(text_width));
// Draw the label
if !r.is_light_rail() {
let name = r.get_name(app.opts().language.as_ref());
if r.length() >= Distance::meters(30.0) && name != "???" {
// TODO If it's definitely straddling bus/bike lanes, change the color? Or
// even easier, just skip the center lines?
let bg = if r.is_private() && app.cs().private_road.is_some() {
if DRAW_CURVEY_LABEL {
let fg = Color::WHITE;
if r.center_pts.quadrant() > 1 && r.center_pts.quadrant() < 4 {
batch.append(Line(name).fg(fg).outlined(Color::BLACK).render_curvey(
prerender,
&r.center_pts.reversed(),
LABEL_SCALE_FACTOR,
));
} else {
batch.append(Line(name).fg(fg).outlined(Color::BLACK).render_curvey(
prerender,
&r.center_pts,
LABEL_SCALE_FACTOR,
));
}
} else {
let center_line_color = if r.is_private() && app.cs().private_road.is_some() {
app.cs()
.zoomed_road_surface(LaneType::Driving, r.get_rank())
.road_center_line
.lerp(app.cs().private_road.unwrap(), 0.5)
} else {
app.cs()
.zoomed_road_surface(LaneType::Driving, r.get_rank())
app.cs().road_center_line
};
// TODO: find a good way to draw an appropriate background
if false {
if r.center_pts.quadrant() > 1 && r.center_pts.quadrant() < 4 {
batch.append(Line(name).fg(center_line_color).render_curvey(
prerender,
&r.center_pts.reversed(),
0.1,
));
} else {
batch.append(Line(name).fg(center_line_color).render_curvey(
prerender,
&r.center_pts,
0.1,
));
}
} else {
let txt = Text::from(Line(name).fg(center_line_color)).bg(bg);
let (pt, angle) = r.center_pts.must_dist_along(r.length() / 2.0);
batch.append(
txt.render_autocropped(prerender)
.scale(0.1)
.centered_on(pt)
.rotate_around_batch_center(angle.reorient()),
);
}
let txt = Text::from(Line(name).fg(center_line_color));
let (pt, angle) = r.center_pts.must_dist_along(r.length() / 2.0);
batch.append(
txt.render_autocropped(prerender)
.scale(LABEL_SCALE_FACTOR)
.centered_on(pt)
.rotate_around_batch_center(angle.reorient()),
);
}
} else {
// No label
batch = render_center_line(app, r, None);
}
// Driveways of connected buildings. These are grouped by road to limit what has to be
@ -163,6 +131,65 @@ impl Renderable for DrawRoad {
}
}
/// If `text_width` is defined, don't draw the center line in the middle of the road for this
/// amount of space
fn render_center_line(app: &dyn AppLike, r: &Road, text_width: Option<Distance>) -> GeomBatch {
let center_line_color = if r.is_private() && app.cs().private_road.is_some() {
app.cs()
.road_center_line
.lerp(app.cs().private_road.unwrap(), 0.5)
} else {
app.cs().road_center_line
};
let mut batch = GeomBatch::new();
// Draw a center line every time two driving/bike/bus lanes of opposite direction are adjacent.
let mut width = Distance::ZERO;
for pair in r.lanes.windows(2) {
width += pair[0].width;
if pair[0].dir != pair[1].dir
&& pair[0].lane_type.is_for_moving_vehicles()
&& pair[1].lane_type.is_for_moving_vehicles()
{
let pl = r.shift_from_left_side(width).unwrap();
if let Some(text_width) = text_width {
// Draw dashed lines from the start of the road to where the text label begins,
// then another set of dashes from where the text label ends to the end of the road
let first_segment_distance = (pl.length() - text_width) / 2.0;
let last_segment_distance = first_segment_distance + text_width;
for slice in [
pl.slice(Distance::ZERO, first_segment_distance),
pl.slice(last_segment_distance, pl.length()),
] {
if let Ok((line, _)) = slice {
batch.extend(
center_line_color,
line.dashed_lines(
Distance::meters(0.25),
Distance::meters(2.0),
Distance::meters(1.0),
),
);
}
}
} else {
// Uninterrupted center line covering the entire road
batch.extend(
center_line_color,
pl.dashed_lines(
Distance::meters(0.25),
Distance::meters(2.0),
Distance::meters(1.0),
),
);
}
}
}
batch
}
fn draw_building_driveway(app: &dyn AppLike, bldg: &Building, batch: &mut GeomBatch) {
if app.opts().camera_angle == CameraAngle::Abstract || !app.opts().show_building_driveways {
return;

View File

@ -311,6 +311,10 @@ impl Text {
self.render(assets).get_dims()
}
pub fn rendered_width<A: AsRef<Assets>>(self, assets: &A) -> f64 {
self.dims(assets.as_ref()).width
}
/// Render the text, without any autocropping. You can pass in an `EventCtx` or `GfxCtx`.
pub fn render<A: AsRef<Assets>>(self, assets: &A) -> GeomBatch {
let assets: &Assets = assets.as_ref();
@ -543,6 +547,11 @@ impl TextSpan {
) -> GeomBatch {
let assets = assets.as_ref();
let tolerance = svg::HIGH_QUALITY;
let mut stroke_parameters = String::new();
if let Some(c) = self.outline_color {
stroke_parameters = format!("stroke=\"{}\" stroke-width=\".1\"", c.as_hex());
};
// Just set a sufficiently large view box
let mut svg = r##"<svg width="9999" height="9999" viewBox="0 0 9999 9999" xmlns="http://www.w3.org/2000/svg">"##.to_string();
@ -564,13 +573,15 @@ impl TextSpan {
}
write!(&mut svg, "\" />").unwrap();
// We need to subtract and account for the length of the text
let start_offset = (path.length() / 2.0).inner_meters()
- (Text::from(&self.text).dims(assets).width * scale) / 2.0;
let start_offset = (path.length().inner_meters()
- scale * Text::from(&self.text).rendered_width(&assets))
/ 2.0;
let fg_color = self.fg_color_for_style(&assets.style.borrow());
write!(
&mut svg,
r##"<text xml:space="preserve" font-size="{}" font-family="{}" {} fill="{}" fill-opacity="{}" startOffset="{}">"##,
r##"<text xml:space="preserve" font-size="{}" font-family="{}" {} fill="{}" fill-opacity="{}" startOffset="{}" {}>"##,
// This is seemingly the easiest way to do this. We could .scale() the whole batch
// after, but then we have to re-translate it to the proper spot
(self.size as f64) * scale,
@ -583,6 +594,7 @@ impl TextSpan {
fg_color.as_hex(),
fg_color.a,
start_offset,
stroke_parameters,
)
.unwrap();