Start LTN tool from the command line. Add a map switcher, so it's usable

standalone.

(It might be worth splitting this out to a separate crate, but not yet)

Also refactor the fading from some of the colorer tools
This commit is contained in:
Dustin Carlino 2021-09-24 12:26:30 -07:00
parent 72e2b39301
commit 8470403d74
7 changed files with 60 additions and 20 deletions

View File

@ -29,7 +29,6 @@ pub use self::routes::PathCostDebugger;
mod blocked_by;
mod floodfill;
mod ltn;
mod objects;
pub mod path_counter;
mod polygons;
@ -611,7 +610,6 @@ impl ContextualActions for Actions {
if cfg!(not(target_arch = "wasm32")) {
actions.push((Key::M, "merge short segment".to_string()));
}
actions.push((Key::L, "LTN mode".to_string()));
}
ID::Intersection(i) => {
actions.push((Key::H, "hide this".to_string()));
@ -813,9 +811,6 @@ impl ContextualActions for Actions {
abstio::write_json("merge_osm_ways.json".to_string(), &ways);
Transition::Push(reimport_map(ctx, app, Some(orig_ways)))
}
(ID::Lane(l), "LTN mode") => {
Transition::Push(ltn::Viewer::start_from_road(ctx, app, l.road))
}
(ID::Area(a), "debug area geometry") => {
let pts = &app.primary.map.get_a(a).polygon.points();
let center = if pts[0] == *pts.last().unwrap() {

View File

@ -29,6 +29,7 @@ mod devtools;
mod edit;
mod info;
mod layer;
mod ltn;
mod pregame;
mod sandbox;
mod ungap;
@ -49,6 +50,7 @@ struct Setup {
load_kml: Option<String>,
diff_map: Option<String>,
ungap: bool,
ltn: bool,
}
fn run(mut settings: Settings) {
@ -80,6 +82,7 @@ fn run(mut settings: Settings) {
load_kml: args.optional("--kml"),
diff_map: args.optional("--diff"),
ungap: args.enabled("--ungap"),
ltn: args.enabled("--ltn"),
};
settings = settings.canvas_settings(setup.opts.canvas_settings.clone());
@ -158,7 +161,8 @@ fn setup_app(ctx: &mut EventCtx, mut setup: Setup) -> (App, Vec<Box<dyn State<Ap
&& !setup.flags.sim_flags.load.contains("player/save")
&& !setup.flags.sim_flags.load.contains("/scenarios/")
&& setup.maybe_mode.is_none()
&& !setup.ungap;
&& !setup.ungap
&& !setup.ltn;
// Load the map used previously if we're starting on the title screen without any overrides.
if title && setup.flags.sim_flags.load == MapName::seattle("montlake").path() {
@ -184,7 +188,7 @@ fn setup_app(ctx: &mut EventCtx, mut setup: Setup) -> (App, Vec<Box<dyn State<Ap
if title {
setup.opts.color_scheme = map_gui::colors::ColorSchemeChoice::Pregame;
}
if setup.ungap {
if setup.ungap || setup.ltn {
setup.opts.color_scheme = map_gui::colors::ColorSchemeChoice::DayMode;
}
let cs = map_gui::colors::ColorScheme::new(ctx, setup.opts.color_scheme);
@ -415,6 +419,8 @@ fn finish_app_setup(
} else if setup.ungap {
let layers = ungap::Layers::new(ctx, app);
vec![ungap::ExploreMap::new_state(ctx, app, layers)]
} else if setup.ltn {
vec![ltn::Viewer::start_anywhere(ctx, app)]
} else {
// Not attempting to keep the primary and secondary simulations synchronized at the same
// time yet. Just handle this one startup case, so we can switch maps without constantly

View File

@ -4,7 +4,7 @@ use geom::Distance;
use map_model::osm::RoadRank;
use map_model::{IntersectionID, Map, PathConstraints, RoadID};
use crate::debug::ltn::{Neighborhood, RatRun};
use crate::ltn::{Neighborhood, RatRun};
impl Neighborhood {
// TODO Doesn't find the full perimeter. But do we really need that?

View File

@ -1,11 +1,11 @@
use std::collections::BTreeSet;
use map_gui::tools::ColorDiscrete;
use map_gui::tools::{nice_map_name, CityPicker, ColorDiscrete};
use map_gui::ID;
use map_model::{IntersectionID, Map, Road, RoadID};
use widgetry::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel,
State, Text, TextExt, VerticalAlignment, Widget,
lctrl, Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line, Outcome,
Panel, State, Text, TextExt, VerticalAlignment, Widget,
};
use crate::app::{App, Transition};
@ -37,14 +37,34 @@ struct RatRun {
}
impl Viewer {
pub fn start_from_road(ctx: &mut EventCtx, app: &App, start: RoadID) -> Box<dyn State<App>> {
pub fn start_anywhere(ctx: &mut EventCtx, app: &App) -> Box<dyn State<App>> {
// Find some residential road to start on
let r = app
.primary
.map
.all_roads()
.iter()
.find(|r| r.get_rank() == map_model::osm::RoadRank::Local)
.unwrap();
Viewer::start_from_road(ctx, app, r.id)
}
fn start_from_road(ctx: &mut EventCtx, app: &App, start: RoadID) -> Box<dyn State<App>> {
let neighborhood = Neighborhood::from_road(&app.primary.map, start);
let (draw_neighborhood, legend) = neighborhood.render(ctx, app);
let rat_runs = neighborhood.find_rat_runs(&app.primary.map);
let panel = Panel::new_builder(Widget::col(vec![
Widget::row(vec![
Line("LTN tool").small_heading().into_widget(ctx),
ctx.style().btn_close_widget(ctx),
ctx.style()
.btn_popup_icon_text(
"system/assets/tools/map.svg",
nice_map_name(app.primary.map.get_name()),
)
.hotkey(lctrl(Key::L))
.build_widget(ctx, "change map")
.centered_vert()
.align_right(),
]),
legend,
"Click a road to re-center".text_widget(ctx),
@ -134,8 +154,12 @@ impl State<App> for Viewer {
if let Outcome::Clicked(x) = self.panel.event(ctx) {
match x.as_ref() {
"close" => {
return Transition::Pop;
"change map" => {
return Transition::Push(CityPicker::new_state(
ctx,
app,
Box::new(|ctx, app| Transition::Replace(Viewer::start_anywhere(ctx, app))),
));
}
"previous rat run" => {
self.current_idx -= 1;
@ -164,7 +188,7 @@ impl Neighborhood {
let interior = Color::BLUE;
let perimeter = Color::hex("#40B5AD");
let border = Color::CYAN;
let mut colorer = ColorDiscrete::new(
let mut colorer = ColorDiscrete::no_fading(
app,
vec![
("interior", interior),

View File

@ -165,6 +165,7 @@ impl Layers {
crate::layer::elevation::SteepStreets::make_colorer(ctx, app);
// The Colorer fades the map as the very first thing in the batch, but we
// don't want to do that twice.
// TODO Can't use no_fading without complicating make_colorer...
colorer.unzoomed.shift();
self.steep_streets = Some(colorer.unzoomed.upload(ctx));
} else {

View File

@ -464,11 +464,8 @@ impl ModeShiftData {
// And convert grams to tons
self.results.annual_co2_emissions_tons = 404.0 * annual_mileage / 907185.0;
let mut colorer = ColorNetwork::new(app);
let mut colorer = ColorNetwork::no_fading(app);
colorer.ranked_roads(count_per_road.clone(), &app.cs.good_to_bad_red);
// The Colorer fades the map as the very first thing in the batch, but we don't want to do
// that twice.
colorer.unzoomed.shift();
let (draw_unzoomed, draw_zoomed) = colorer.build(ctx);
self.gaps = NetworkGaps {
draw_unzoomed,

View File

@ -38,6 +38,15 @@ impl<'a> ColorDiscrete<'a> {
}
}
pub fn no_fading<I: Into<String>>(
app: &'a dyn AppLike,
categories: Vec<(I, Color)>,
) -> ColorDiscrete<'a> {
let mut c = ColorDiscrete::new(app, categories);
c.unzoomed = GeomBatch::new();
c
}
pub fn add_l<I: AsRef<str>>(&mut self, l: LaneID, category: I) {
let color = self.colors[category.as_ref()];
self.unzoomed
@ -270,6 +279,14 @@ impl<'a> ColorNetwork<'a> {
}
}
pub fn no_fading(app: &'a dyn AppLike) -> ColorNetwork {
ColorNetwork {
map: app.map(),
unzoomed: GeomBatch::new(),
zoomed: GeomBatch::new(),
}
}
pub fn add_l(&mut self, l: LaneID, color: Color) {
self.unzoomed
.push(color, self.map.get_parent(l).get_thick_polygon());