mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-23 14:23:14 +03:00
* 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:
parent
8f49dddaee
commit
ee7f843ff6
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user