mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
Preview cell connectivity from the browse neighborhoods screen
This commit is contained in:
parent
6b79201d21
commit
973f733d36
@ -1,15 +1,14 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use abstutil::Timer;
|
|
||||||
use geom::Distance;
|
use geom::Distance;
|
||||||
use map_gui::tools::{CityPicker, DrawRoadLabels, Navigator, PopupMsg, URLManager};
|
use map_gui::tools::{CityPicker, DrawRoadLabels, Navigator, PopupMsg, URLManager};
|
||||||
use widgetry::mapspace::{ToggleZoomed, World, WorldOutcome};
|
use widgetry::mapspace::{ToggleZoomed, World, WorldOutcome};
|
||||||
use widgetry::{
|
use widgetry::{
|
||||||
lctrl, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Outcome, Panel, State, TextExt,
|
lctrl, Choice, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Outcome, Panel, State,
|
||||||
Toggle, VerticalAlignment, Widget,
|
TextExt, Toggle, VerticalAlignment, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{NeighborhoodID, Partitioning};
|
use super::{Neighborhood, NeighborhoodID, Partitioning};
|
||||||
use crate::app::{App, Transition};
|
use crate::app::{App, Transition};
|
||||||
use crate::debug::DebugMode;
|
use crate::debug::DebugMode;
|
||||||
|
|
||||||
@ -25,8 +24,14 @@ impl BrowseNeighborhoods {
|
|||||||
pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> {
|
pub fn new_state(ctx: &mut EventCtx, app: &mut App) -> Box<dyn State<App>> {
|
||||||
URLManager::update_url_map_name(app);
|
URLManager::update_url_map_name(app);
|
||||||
|
|
||||||
|
let style = Style::SimpleColoring;
|
||||||
let world = ctx.loading_screen("calculate neighborhoods", |ctx, timer| {
|
let world = ctx.loading_screen("calculate neighborhoods", |ctx, timer| {
|
||||||
detect_neighborhoods(ctx, app, timer)
|
// TODO Or if the map doesn't match? Do we take care of this in SessionState for
|
||||||
|
// anything?!
|
||||||
|
if app.session.partitioning.neighborhoods.is_empty() {
|
||||||
|
app.session.partitioning = Partitioning::seed_using_heuristics(app, timer);
|
||||||
|
}
|
||||||
|
make_world(ctx, app, style)
|
||||||
});
|
});
|
||||||
let draw_all_filters = app.session.modal_filters.draw(ctx, &app.primary.map, None);
|
let draw_all_filters = app.session.modal_filters.draw(ctx, &app.primary.map, None);
|
||||||
|
|
||||||
@ -42,6 +47,18 @@ impl BrowseNeighborhoods {
|
|||||||
.align_right(),
|
.align_right(),
|
||||||
]),
|
]),
|
||||||
Toggle::checkbox(ctx, "highlight boundary roads", Key::H, true),
|
Toggle::checkbox(ctx, "highlight boundary roads", Key::H, true),
|
||||||
|
Widget::row(vec![
|
||||||
|
"Draw neighborhoods:".text_widget(ctx).centered_vert(),
|
||||||
|
Widget::dropdown(
|
||||||
|
ctx,
|
||||||
|
"style",
|
||||||
|
style,
|
||||||
|
vec![
|
||||||
|
Choice::new("simple", Style::SimpleColoring),
|
||||||
|
Choice::new("cells", Style::Cells),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]),
|
||||||
ctx.style()
|
ctx.style()
|
||||||
.btn_outline
|
.btn_outline
|
||||||
.text("Export to GeoJSON")
|
.text("Export to GeoJSON")
|
||||||
@ -61,8 +78,8 @@ impl BrowseNeighborhoods {
|
|||||||
|
|
||||||
impl State<App> for BrowseNeighborhoods {
|
impl State<App> for BrowseNeighborhoods {
|
||||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||||
if let Outcome::Clicked(x) = self.panel.event(ctx) {
|
match self.panel.event(ctx) {
|
||||||
match x.as_ref() {
|
Outcome::Clicked(x) => match x.as_ref() {
|
||||||
"Home" => {
|
"Home" => {
|
||||||
return Transition::Clear(vec![crate::pregame::TitleScreen::new_state(
|
return Transition::Clear(vec![crate::pregame::TitleScreen::new_state(
|
||||||
ctx, app,
|
ctx, app,
|
||||||
@ -99,7 +116,13 @@ impl State<App> for BrowseNeighborhoods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
Outcome::Changed(_) => {
|
||||||
|
self.world = ctx.loading_screen("change style", |ctx, _| {
|
||||||
|
make_world(ctx, app, self.panel.dropdown_value("style"))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let WorldOutcome::ClickedObject(id) = self.world.event(ctx) {
|
if let WorldOutcome::ClickedObject(id) = self.world.event(ctx) {
|
||||||
@ -126,25 +149,35 @@ impl State<App> for BrowseNeighborhoods {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_neighborhoods(
|
fn make_world(ctx: &mut EventCtx, app: &App, style: Style) -> World<NeighborhoodID> {
|
||||||
ctx: &mut EventCtx,
|
|
||||||
app: &mut App,
|
|
||||||
timer: &mut Timer,
|
|
||||||
) -> World<NeighborhoodID> {
|
|
||||||
// TODO Or if the map doesn't match? Do we take care of this in SessionState for anything?!
|
|
||||||
if app.session.partitioning.neighborhoods.is_empty() {
|
|
||||||
app.session.partitioning = Partitioning::seed_using_heuristics(app, timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut world = World::bounded(app.primary.map.get_bounds());
|
let mut world = World::bounded(app.primary.map.get_bounds());
|
||||||
for (id, (block, color)) in &app.session.partitioning.neighborhoods {
|
for (id, (block, color)) in &app.session.partitioning.neighborhoods {
|
||||||
world
|
match style {
|
||||||
.add(*id)
|
Style::SimpleColoring => {
|
||||||
.hitbox(block.polygon.clone())
|
world
|
||||||
.draw_color(color.alpha(0.5))
|
.add(*id)
|
||||||
.hover_outline(Color::BLACK, Distance::meters(5.0))
|
.hitbox(block.polygon.clone())
|
||||||
.clickable()
|
.draw_color(color.alpha(0.5))
|
||||||
.build(ctx);
|
.hover_outline(Color::BLACK, Distance::meters(5.0))
|
||||||
|
.clickable()
|
||||||
|
.build(ctx);
|
||||||
|
}
|
||||||
|
Style::Cells => {
|
||||||
|
// TODO The cell colors are confusing alongside the other neighborhood colors. I
|
||||||
|
// tried greying out everything else, but then the view is too jumpy.
|
||||||
|
let map = &app.primary.map;
|
||||||
|
let neighborhood = Neighborhood::new(ctx, app, *id);
|
||||||
|
let render_cells = super::draw_cells::RenderCells::new(map, &neighborhood);
|
||||||
|
let hovered_batch = render_cells.draw_grid();
|
||||||
|
world
|
||||||
|
.add(*id)
|
||||||
|
.hitbox(block.polygon.clone())
|
||||||
|
.draw_color(color.alpha(0.5))
|
||||||
|
.draw_hovered(hovered_batch)
|
||||||
|
.clickable()
|
||||||
|
.build(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
world
|
world
|
||||||
}
|
}
|
||||||
@ -186,3 +219,9 @@ fn draw_boundary_roads(ctx: &EventCtx, app: &App) -> ToggleZoomed {
|
|||||||
}
|
}
|
||||||
batch.build(ctx)
|
batch.build(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
enum Style {
|
||||||
|
SimpleColoring,
|
||||||
|
Cells,
|
||||||
|
}
|
||||||
|
@ -170,7 +170,7 @@ fn find_cells(
|
|||||||
no_car_roads.push(start);
|
no_car_roads.push(start);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let cell = floodfill(map, start, perimeter, borders, &modal_filters);
|
let cell = floodfill(map, start, borders, &modal_filters);
|
||||||
visited.extend(cell.roads.keys().cloned());
|
visited.extend(cell.roads.keys().cloned());
|
||||||
cells.push(cell);
|
cells.push(cell);
|
||||||
}
|
}
|
||||||
@ -244,7 +244,6 @@ fn find_cells(
|
|||||||
fn floodfill(
|
fn floodfill(
|
||||||
map: &Map,
|
map: &Map,
|
||||||
start: RoadID,
|
start: RoadID,
|
||||||
perimeter: &Perimeter,
|
|
||||||
neighborhood_borders: &BTreeSet<IntersectionID>,
|
neighborhood_borders: &BTreeSet<IntersectionID>,
|
||||||
modal_filters: &ModalFilters,
|
modal_filters: &ModalFilters,
|
||||||
) -> Cell {
|
) -> Cell {
|
||||||
|
Loading…
Reference in New Issue
Block a user