At really low zoom levels, draw modal filters using the scale-invariant

circles. Otherwise they're just impossible to see. Since they're the
most important thing to show in the LTN tool, seems worth it.

This helps proceed on #851
This commit is contained in:
Dustin Carlino 2022-02-02 09:20:10 +00:00
parent 067fdb8649
commit 635f508540
5 changed files with 54 additions and 18 deletions

View File

@ -11,13 +11,13 @@ use widgetry::{
}; };
use super::{Neighborhood, NeighborhoodID, Partitioning}; use super::{Neighborhood, NeighborhoodID, Partitioning};
use crate::{App, ModalFilters, Transition}; use crate::{App, ModalFilters, Toggle3Zoomed, Transition};
pub struct BrowseNeighborhoods { pub struct BrowseNeighborhoods {
panel: Panel, panel: Panel,
world: World<NeighborhoodID>, world: World<NeighborhoodID>,
labels: DrawRoadLabels, labels: DrawRoadLabels,
draw_all_filters: ToggleZoomed, draw_all_filters: Toggle3Zoomed,
draw_boundary_roads: ToggleZoomed, draw_boundary_roads: ToggleZoomed,
} }
@ -173,10 +173,10 @@ impl State<App> for BrowseNeighborhoods {
crate::draw_with_layering(g, app, |g| self.world.draw(g)); crate::draw_with_layering(g, app, |g| self.world.draw(g));
self.panel.draw(g); self.panel.draw(g);
self.draw_all_filters.draw(g);
if self.panel.is_checked("highlight boundary roads") { if self.panel.is_checked("highlight boundary roads") {
self.draw_boundary_roads.draw(g); self.draw_boundary_roads.draw(g);
} }
self.draw_all_filters.draw(g);
if g.canvas.is_unzoomed() { if g.canvas.is_unzoomed() {
self.labels.draw(g, app); self.labels.draw(g, app);
} }
@ -249,7 +249,7 @@ fn draw_boundary_roads(ctx: &EventCtx, app: &App) -> ToggleZoomed {
let road = app.map.get_r(r); let road = app.map.get_r(r);
batch batch
.unzoomed .unzoomed
.push(Color::RED.alpha(0.8), road.get_thick_polygon()); .push(Color::RED.alpha(0.6), road.get_thick_polygon());
batch batch
.zoomed .zoomed
.push(Color::RED.alpha(0.5), road.get_thick_polygon()); .push(Color::RED.alpha(0.5), road.get_thick_polygon());
@ -261,7 +261,7 @@ fn draw_boundary_roads(ctx: &EventCtx, app: &App) -> ToggleZoomed {
seen_borders.insert(i); seen_borders.insert(i);
batch batch
.unzoomed .unzoomed
.push(Color::RED.alpha(0.8), app.map.get_i(i).polygon.clone()); .push(Color::RED.alpha(0.6), app.map.get_i(i).polygon.clone());
batch batch
.zoomed .zoomed
.push(Color::RED.alpha(0.5), app.map.get_i(i).polygon.clone()); .push(Color::RED.alpha(0.5), app.map.get_i(i).polygon.clone());

View File

@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use geom::{Circle, Distance, Line}; use geom::{Circle, Distance, Line};
use map_model::{IntersectionID, Map, RoadID, RoutingParams, TurnID}; use map_model::{IntersectionID, Map, RoadID, RoutingParams, TurnID};
use widgetry::mapspace::ToggleZoomed; use widgetry::mapspace::{DrawUnzoomedShapes, ToggleZoomed};
use widgetry::{Color, EventCtx, GeomBatch}; use widgetry::{Color, EventCtx, GeomBatch, GfxCtx};
use super::Neighborhood; use super::Neighborhood;
use crate::App; use crate::App;
@ -88,8 +88,10 @@ impl ModalFilters {
ctx: &EventCtx, ctx: &EventCtx,
map: &Map, map: &Map,
only_neighborhood: Option<&Neighborhood>, only_neighborhood: Option<&Neighborhood>,
) -> ToggleZoomed { ) -> Toggle3Zoomed {
let mut batch = ToggleZoomed::builder(); let mut batch = ToggleZoomed::builder();
let mut low_zoom = DrawUnzoomedShapes::builder();
for (r, dist) in &self.roads { for (r, dist) in &self.roads {
if only_neighborhood if only_neighborhood
.map(|n| !n.orig_perimeter.interior.contains(r)) .map(|n| !n.orig_perimeter.interior.contains(r))
@ -102,6 +104,11 @@ impl ModalFilters {
if let Ok((pt, angle)) = road.center_pts.dist_along(*dist) { if let Ok((pt, angle)) = road.center_pts.dist_along(*dist) {
let road_width = road.get_width(); let road_width = road.get_width();
// TODO DrawUnzoomedShapes can do lines, but they don't stretch as the radius does,
// so it looks weird
low_zoom.add_circle(pt, Distance::meters(8.0), Color::RED);
low_zoom.add_circle(pt, Distance::meters(6.0), Color::WHITE);
batch batch
.unzoomed .unzoomed
.push(Color::RED, Circle::new(pt, road_width).to_polygon()); .push(Color::RED, Circle::new(pt, road_width).to_polygon());
@ -134,6 +141,13 @@ impl ModalFilters {
} }
let line = filter.geometry(map); let line = filter.geometry(map);
// It's really hard to see a tiny squished line thickened, so use the same circle
// symbology at really low zooms
let pt = line.middle().unwrap();
low_zoom.add_circle(pt, Distance::meters(8.0), Color::RED);
low_zoom.add_circle(pt, Distance::meters(6.0), Color::WHITE);
batch batch
.unzoomed .unzoomed
.push(Color::RED, line.make_polygons(Distance::meters(3.0))); .push(Color::RED, line.make_polygons(Distance::meters(3.0)));
@ -144,7 +158,7 @@ impl ModalFilters {
line.percent_slice(0.3, 0.7).unwrap_or(line), line.percent_slice(0.3, 0.7).unwrap_or(line),
); );
} }
batch.build(ctx) Toggle3Zoomed::new(batch.build(ctx), low_zoom.build())
} }
} }
@ -250,3 +264,27 @@ fn draw_zoomed_planters(ctx: &EventCtx, batch: &mut GeomBatch, line: Line) {
.rotate(line.angle()), .rotate(line.angle()),
); );
} }
/// Depending on the canvas zoom level, draws one of 3 things.
pub struct Toggle3Zoomed {
draw: ToggleZoomed,
unzoomed: DrawUnzoomedShapes,
}
impl Toggle3Zoomed {
fn new(draw: ToggleZoomed, unzoomed: DrawUnzoomedShapes) -> Self {
Self { draw, unzoomed }
}
pub fn empty(ctx: &EventCtx) -> Self {
Self::new(ToggleZoomed::empty(ctx), DrawUnzoomedShapes::empty())
}
pub fn draw(&self, g: &mut GfxCtx) {
if g.canvas.cam_zoom < 1.0 {
self.unzoomed.draw(g);
} else {
self.draw.draw(g);
}
}
}

View File

@ -3,21 +3,20 @@ use std::collections::BTreeSet;
use map_gui::load::FileLoader; use map_gui::load::FileLoader;
use map_gui::tools::{checkbox_per_mode, PopupMsg}; use map_gui::tools::{checkbox_per_mode, PopupMsg};
use synthpop::{Scenario, TripMode}; use synthpop::{Scenario, TripMode};
use widgetry::mapspace::ToggleZoomed;
use widgetry::{ use widgetry::{
Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Panel, SimpleState, Slider, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Line, Panel, SimpleState, Slider,
State, Text, TextExt, Toggle, VerticalAlignment, Widget, State, Text, TextExt, Toggle, VerticalAlignment, Widget,
}; };
use super::{end_of_day, Filters, Impact}; use super::{end_of_day, Filters, Impact};
use crate::{App, BrowseNeighborhoods, Transition}; use crate::{App, BrowseNeighborhoods, Toggle3Zoomed, Transition};
// TODO Share structure or pieces with Ungap's predict mode // TODO Share structure or pieces with Ungap's predict mode
// ... can't we just produce data of a certain shape, and have a UI pretty tuned for that? // ... can't we just produce data of a certain shape, and have a UI pretty tuned for that?
pub struct ShowResults { pub struct ShowResults {
draw_all_neighborhoods: Drawable, draw_all_neighborhoods: Drawable,
draw_all_filters: ToggleZoomed, draw_all_filters: Toggle3Zoomed,
} }
impl ShowResults { impl ShowResults {

View File

@ -5,7 +5,7 @@ use structopt::StructOpt;
use widgetry::{GfxCtx, Settings}; use widgetry::{GfxCtx, Settings};
pub use browse::BrowseNeighborhoods; pub use browse::BrowseNeighborhoods;
pub use filters::{DiagonalFilter, ModalFilters}; pub use filters::{DiagonalFilter, ModalFilters, Toggle3Zoomed};
pub use neighborhood::{Cell, DistanceInterval, Neighborhood}; pub use neighborhood::{Cell, DistanceInterval, Neighborhood};
pub use partition::{NeighborhoodID, Partitioning}; pub use partition::{NeighborhoodID, Partitioning};
@ -63,7 +63,7 @@ fn run(mut settings: Settings) {
impact: impact::Impact::empty(ctx), impact: impact::Impact::empty(ctx),
highlight_boundary_roads: true, highlight_boundary_roads: false,
draw_neighborhood_style: browse::Style::SimpleColoring, draw_neighborhood_style: browse::Style::SimpleColoring,
draw_cells_as_areas: true, draw_cells_as_areas: true,
draw_borders_as_arrows: true, draw_borders_as_arrows: true,

View File

@ -5,10 +5,9 @@ use maplit::btreeset;
use geom::{Distance, Polygon}; use geom::{Distance, Polygon};
use map_gui::tools::DrawRoadLabels; use map_gui::tools::DrawRoadLabels;
use map_model::{IntersectionID, Map, PathConstraints, Perimeter, RoadID}; use map_model::{IntersectionID, Map, PathConstraints, Perimeter, RoadID};
use widgetry::mapspace::ToggleZoomed;
use widgetry::{Drawable, EventCtx, GeomBatch}; use widgetry::{Drawable, EventCtx, GeomBatch};
use crate::{App, ModalFilters, NeighborhoodID}; use crate::{App, ModalFilters, NeighborhoodID, Toggle3Zoomed};
pub struct Neighborhood { pub struct Neighborhood {
pub id: NeighborhoodID, pub id: NeighborhoodID,
@ -24,7 +23,7 @@ pub struct Neighborhood {
pub cells: Vec<Cell>, pub cells: Vec<Cell>,
pub fade_irrelevant: Drawable, pub fade_irrelevant: Drawable,
pub draw_filters: ToggleZoomed, pub draw_filters: Toggle3Zoomed,
pub labels: DrawRoadLabels, pub labels: DrawRoadLabels,
} }
@ -74,7 +73,7 @@ impl Neighborhood {
cells: Vec::new(), cells: Vec::new(),
fade_irrelevant: Drawable::empty(ctx), fade_irrelevant: Drawable::empty(ctx),
draw_filters: ToggleZoomed::empty(ctx), draw_filters: Toggle3Zoomed::empty(ctx),
// Temporary value // Temporary value
labels: DrawRoadLabels::only_major_roads(), labels: DrawRoadLabels::only_major_roads(),
}; };