mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 15:02:59 +03:00
In the LTN browse and connectivity tool, draw the areas after the map
background and water/parks, but before everything else. It's much easier to understand the actual basemap this way -- you can see roads clearly.
This commit is contained in:
parent
e5704f4a6d
commit
e0b6e94f26
@ -6,8 +6,8 @@ use map_gui::tools::{CityPicker, DrawRoadLabels, Navigator, PopupMsg, URLManager
|
||||
use synthpop::Scenario;
|
||||
use widgetry::mapspace::{ToggleZoomed, World, WorldOutcome};
|
||||
use widgetry::{
|
||||
Choice, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text,
|
||||
TextExt, Toggle, VerticalAlignment, Widget,
|
||||
Choice, Color, DrawBaselayer, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel,
|
||||
State, Text, TextExt, Toggle, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use super::{Neighborhood, NeighborhoodID, Partitioning};
|
||||
@ -165,9 +165,14 @@ impl State<App> for BrowseNeighborhoods {
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw_baselayer(&self) -> DrawBaselayer {
|
||||
DrawBaselayer::Custom
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
crate::draw_with_layering(g, app, |g| self.world.draw(g));
|
||||
|
||||
self.panel.draw(g);
|
||||
self.world.draw(g);
|
||||
self.draw_all_filters.draw(g);
|
||||
if self.panel.is_checked("highlight boundary roads") {
|
||||
self.draw_boundary_roads.draw(g);
|
||||
@ -187,7 +192,7 @@ fn make_world(ctx: &mut EventCtx, app: &App, timer: &mut Timer) -> World<Neighbo
|
||||
world
|
||||
.add(*id)
|
||||
.hitbox(block.polygon.clone())
|
||||
.draw_color(color.alpha(0.5))
|
||||
.draw_color(color.alpha(0.3))
|
||||
.hover_outline(Color::BLACK, Distance::meters(5.0))
|
||||
.clickable()
|
||||
.build(ctx);
|
||||
|
@ -1,6 +1,9 @@
|
||||
use geom::{Angle, ArrowCap, Distance, PolyLine};
|
||||
use widgetry::mapspace::World;
|
||||
use widgetry::{EventCtx, GeomBatch, GfxCtx, Key, Outcome, Panel, State, TextExt, Toggle, Widget};
|
||||
use widgetry::{
|
||||
DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Outcome, Panel, State, TextExt,
|
||||
Toggle, Widget,
|
||||
};
|
||||
|
||||
use super::auto::Heuristic;
|
||||
use super::per_neighborhood::{FilterableObj, Tab};
|
||||
@ -11,6 +14,7 @@ pub struct Viewer {
|
||||
panel: Panel,
|
||||
neighborhood: Neighborhood,
|
||||
world: World<FilterableObj>,
|
||||
draw_top_layer: Drawable,
|
||||
}
|
||||
|
||||
impl Viewer {
|
||||
@ -21,6 +25,7 @@ impl Viewer {
|
||||
panel: Panel::empty(ctx),
|
||||
neighborhood,
|
||||
world: World::unbounded(),
|
||||
draw_top_layer: Drawable::empty(ctx),
|
||||
};
|
||||
viewer.update(ctx, app);
|
||||
Box::new(viewer)
|
||||
@ -84,7 +89,9 @@ impl Viewer {
|
||||
)
|
||||
.build(ctx);
|
||||
|
||||
self.world = make_world(ctx, app, &self.neighborhood);
|
||||
let (world, draw_top_layer) = make_world(ctx, app, &self.neighborhood);
|
||||
self.world = world;
|
||||
self.draw_top_layer = draw_top_layer;
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +120,9 @@ impl State<App> for Viewer {
|
||||
app.session.heuristic = self.panel.dropdown_value("heuristic");
|
||||
|
||||
if x != "heuristic" {
|
||||
self.world = make_world(ctx, app, &self.neighborhood);
|
||||
let (world, draw_top_layer) = make_world(ctx, app, &self.neighborhood);
|
||||
self.world = world;
|
||||
self.draw_top_layer = draw_top_layer;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -128,10 +137,17 @@ impl State<App> for Viewer {
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw_baselayer(&self) -> DrawBaselayer {
|
||||
DrawBaselayer::Custom
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
self.panel.draw(g);
|
||||
crate::draw_with_layering(g, app, |g| self.world.draw(g));
|
||||
g.redraw(&self.draw_top_layer);
|
||||
// TODO This covers up the arrows
|
||||
g.redraw(&self.neighborhood.fade_irrelevant);
|
||||
self.world.draw(g);
|
||||
|
||||
self.panel.draw(g);
|
||||
self.neighborhood.draw_filters.draw(g);
|
||||
// TODO Since we cover such a small area, treating multiple segments of one road as the
|
||||
// same might be nice. And we should seed the quadtree with the locations of filters and
|
||||
@ -142,22 +158,29 @@ impl State<App> for Viewer {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_world(ctx: &mut EventCtx, app: &App, neighborhood: &Neighborhood) -> World<FilterableObj> {
|
||||
fn make_world(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
neighborhood: &Neighborhood,
|
||||
) -> (World<FilterableObj>, Drawable) {
|
||||
let map = &app.map;
|
||||
let mut world = World::bounded(map.get_bounds());
|
||||
|
||||
super::per_neighborhood::populate_world(ctx, app, neighborhood, &mut world, |id| id, 0);
|
||||
|
||||
// The world is drawn in between areas and roads, but some things need to be drawn on top of
|
||||
// roads
|
||||
let mut draw_top_layer = GeomBatch::new();
|
||||
|
||||
let render_cells = super::draw_cells::RenderCells::new(map, neighborhood);
|
||||
if app.session.draw_cells_as_areas {
|
||||
world.draw_master_batch(ctx, render_cells.draw());
|
||||
} else {
|
||||
let mut draw = GeomBatch::new();
|
||||
for (idx, cell) in neighborhood.cells.iter().enumerate() {
|
||||
let color = render_cells.colors[idx].alpha(0.9);
|
||||
for (r, interval) in &cell.roads {
|
||||
let road = map.get_r(*r);
|
||||
draw.push(
|
||||
draw_top_layer.push(
|
||||
color,
|
||||
road.center_pts
|
||||
.exact_slice(interval.start, interval.end)
|
||||
@ -167,14 +190,12 @@ fn make_world(ctx: &mut EventCtx, app: &App, neighborhood: &Neighborhood) -> Wor
|
||||
for i in
|
||||
map_gui::tools::intersections_from_roads(&cell.roads.keys().cloned().collect(), map)
|
||||
{
|
||||
draw.push(color, map.get_i(i).polygon.clone());
|
||||
draw_top_layer.push(color, map.get_i(i).polygon.clone());
|
||||
}
|
||||
}
|
||||
world.draw_master_batch(ctx, draw);
|
||||
}
|
||||
|
||||
// Draw the borders of each cell
|
||||
let mut draw = GeomBatch::new();
|
||||
for (idx, cell) in neighborhood.cells.iter().enumerate() {
|
||||
let color = render_cells.colors[idx];
|
||||
for i in &cell.borders {
|
||||
@ -207,7 +228,7 @@ fn make_world(ctx: &mut EventCtx, app: &App, neighborhood: &Neighborhood) -> Wor
|
||||
|
||||
// TODO Consider showing borders with one-way roads. For now, always point the
|
||||
// arrow into the neighborhood
|
||||
draw.push(
|
||||
draw_top_layer.push(
|
||||
color.alpha(0.8),
|
||||
PolyLine::must_new(vec![
|
||||
center.project_away(Distance::meters(30.0), angle.opposite()),
|
||||
@ -216,13 +237,12 @@ fn make_world(ctx: &mut EventCtx, app: &App, neighborhood: &Neighborhood) -> Wor
|
||||
.make_arrow(Distance::meters(6.0), ArrowCap::Triangle),
|
||||
);
|
||||
} else if let Ok(p) = map.get_i(*i).polygon.to_outline(Distance::meters(2.0)) {
|
||||
draw.push(color, p);
|
||||
draw_top_layer.push(color, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
world.draw_master_batch(ctx, draw);
|
||||
|
||||
world.initialize_hover(ctx);
|
||||
|
||||
world
|
||||
(world, ctx.upload(draw_top_layer))
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
use widgetry::Settings;
|
||||
use widgetry::{GfxCtx, Settings};
|
||||
|
||||
pub use browse::BrowseNeighborhoods;
|
||||
pub use filters::{DiagonalFilter, ModalFilters};
|
||||
@ -136,3 +136,36 @@ pub struct Session {
|
||||
|
||||
current_trip_name: Option<String>,
|
||||
}
|
||||
|
||||
/// Do the equivalent of `SimpleApp::draw_unzoomed` or `draw_zoomed`, but after the water/park
|
||||
/// areas layer, draw something custom.
|
||||
fn draw_with_layering<F: Fn(&mut GfxCtx)>(g: &mut GfxCtx, app: &App, custom: F) {
|
||||
g.clear(app.cs.void_background);
|
||||
g.redraw(&app.draw_map.boundary_polygon);
|
||||
g.redraw(&app.draw_map.draw_all_areas);
|
||||
custom(g);
|
||||
|
||||
if g.canvas.is_unzoomed() {
|
||||
g.redraw(&app.draw_map.draw_all_unzoomed_parking_lots);
|
||||
g.redraw(&app.draw_map.draw_all_unzoomed_roads_and_intersections);
|
||||
g.redraw(&app.draw_map.draw_all_buildings);
|
||||
g.redraw(&app.draw_map.draw_all_building_outlines);
|
||||
} else {
|
||||
let options = map_gui::render::DrawOptions::new();
|
||||
let objects = app
|
||||
.draw_map
|
||||
.get_renderables_back_to_front(g.get_screen_bounds(), &app.map);
|
||||
|
||||
let mut drawn_all_buildings = false;
|
||||
|
||||
for obj in objects {
|
||||
obj.draw(g, app, &options);
|
||||
|
||||
if matches!(obj.get_id(), map_gui::ID::Building(_)) && !drawn_all_buildings {
|
||||
g.redraw(&app.draw_map.draw_all_buildings);
|
||||
g.redraw(&app.draw_map.draw_all_building_outlines);
|
||||
drawn_all_buildings = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user