Split the controls experiment into a separate binary, get it to draw a

map way more simply than the game
This commit is contained in:
Dustin Carlino 2020-11-23 09:27:07 -08:00
parent 558eb6f716
commit ab2f6fefec
31 changed files with 288 additions and 90 deletions

9
Cargo.lock generated
View File

@ -705,6 +705,15 @@ dependencies = [
"num-traits 0.2.12",
]
[[package]]
name = "experiment"
version = "0.1.0"
dependencies = [
"geom",
"map_gui",
"widgetry",
]
[[package]]
name = "failure"
version = "0.1.8"

View File

@ -4,6 +4,7 @@ members = [
"abstutil",
"collisions",
"convert_osm",
"experiment",
"game",
"geom",
"headless",

View File

@ -139,6 +139,7 @@ Other:
- `collisions`: an experimental data format for real-world collision data
- `traffic_seitan`: a bug-finding tool that randomly generates live map edits
- `tests`: integration tests
- `experiment`: ...
## Code conventions

13
experiment/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "experiment"
version = "0.1.0"
authors = ["Dustin Carlino <dabreegster@gmail.com>"]
edition = "2018"
[features]
default = ["widgetry/native-backend"]
[dependencies]
geom = { path = "../geom" }
map_gui = { path = "../map_gui" }
widgetry = { path = "../widgetry" }

View File

@ -1,21 +1,19 @@
use geom::{Angle, Circle, Distance, Pt2D, Speed};
use map_gui::SimpleApp;
use widgetry::{
Btn, Checkbox, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State,
UpdateType, VerticalAlignment, Widget,
Transition, UpdateType, VerticalAlignment, Widget,
};
use crate::app::App;
use crate::game::Transition;
pub struct Experiment {
pub struct Game {
panel: Panel,
controls: Box<dyn Controller>,
sleigh: Pt2D,
}
impl Experiment {
pub fn new(ctx: &mut EventCtx) -> Box<dyn State<App>> {
Box::new(Experiment {
impl Game {
pub fn new(ctx: &mut EventCtx) -> Box<dyn State<SimpleApp>> {
Box::new(Game {
panel: Panel::new(Widget::col(vec![
Widget::row(vec![
Line("Experiment").small_heading().draw(ctx),
@ -31,8 +29,8 @@ impl Experiment {
}
}
impl State<App> for Experiment {
fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Transition {
impl State<SimpleApp> for Game {
fn event(&mut self, ctx: &mut EventCtx, _: &mut SimpleApp) -> Transition<SimpleApp> {
let (dx, dy) = self.controls.displacement(ctx);
self.sleigh = self.sleigh.offset(dx, dy);
ctx.canvas.center_on_map_pt(self.sleigh);
@ -58,7 +56,7 @@ impl State<App> for Experiment {
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &App) {
fn draw(&self, g: &mut GfxCtx, _: &SimpleApp) {
self.panel.draw(g);
g.draw_polygon(

9
experiment/src/main.rs Normal file
View File

@ -0,0 +1,9 @@
mod game;
fn main() {
widgetry::run(widgetry::Settings::new("experiment"), |ctx| {
ctx.canvas.cam_zoom = 10.0; // TODO
let app = map_gui::SimpleApp::new(ctx);
(app, vec![game::Game::new(ctx)])
});
}

View File

@ -6,6 +6,9 @@ use rand::seq::SliceRandom;
use abstutil::{MapName, Timer};
use geom::{Bounds, Circle, Distance, Duration, Pt2D, Time};
use map_gui::colors::ColorScheme;
use map_gui::options::Options;
use map_gui::render::{unzoomed_agent_radius, AgentCache, DrawMap, DrawOptions, Renderable};
use map_model::{IntersectionID, Map, Traversable};
use sim::{AgentID, Analytics, Scenario, Sim, SimCallback, SimFlags};
use widgetry::{Canvas, EventCtx, GfxCtx, Prerender, SharedAppState};
@ -15,11 +18,6 @@ use crate::edit::apply_map_edits;
use crate::helpers::ID;
use crate::layer::Layer;
use crate::sandbox::{GameplayMode, TutorialState};
use map_gui::colors::{ColorScheme, ColorSchemeChoice};
use map_gui::options::Options;
use map_gui::render::{
unzoomed_agent_radius, AgentCache, DrawMap, DrawOptions, Renderable, UnzoomedAgents,
};
/// The top-level data that lasts through the entire game, no matter what state the game is in.
pub struct App {
@ -454,6 +452,10 @@ impl map_gui::AppLike for App {
&self.cs
}
#[inline]
fn mut_cs(&mut self) -> &mut ColorScheme {
&mut self.cs
}
#[inline]
fn draw_map(&self) -> &DrawMap {
&self.primary.draw_map
}
@ -469,24 +471,6 @@ impl map_gui::AppLike for App {
fn mut_opts(&mut self) -> &mut Options {
&mut self.opts
}
#[inline]
fn unzoomed_agents(&self) -> &UnzoomedAgents {
&self.unzoomed_agents
}
fn change_color_scheme(&mut self, ctx: &mut EventCtx, cs: ColorSchemeChoice) -> bool {
if self.opts.color_scheme == cs {
return false;
}
self.opts.color_scheme = cs;
self.cs = ColorScheme::new(ctx, self.opts.color_scheme);
ctx.loading_screen("rerendering map colors", |ctx, timer| {
self.primary.draw_map =
DrawMap::new(&self.primary.map, &self.opts, &self.cs, ctx, timer);
});
true
}
}
pub struct ShowLayers {

View File

@ -1,5 +1,6 @@
use abstutil::{prettyprint_usize, MapName};
use geom::{Distance, Percent, Polygon, Pt2D};
use map_gui::render::DrawArea;
use map_model::City;
use widgetry::{
Autocomplete, Btn, Color, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome,
@ -10,7 +11,6 @@ use crate::app::App;
use crate::game::Transition;
use crate::helpers::{grey_out_map, nice_map_name, open_browser};
use crate::load::MapLoader;
use map_gui::render::DrawArea;
pub struct CityPicker {
panel: Panel,

View File

@ -2,6 +2,8 @@ use std::collections::HashSet;
use abstutil::{MapName, Parallelism, Tags, Timer};
use geom::{Distance, Pt2D};
use map_gui::options::OptionsPanel;
use map_gui::render::{calculate_corners, DrawOptions};
use map_model::{osm, ControlTrafficSignal, NORMAL_LANE_THICKNESS};
use sim::{AgentID, Sim};
use widgetry::{
@ -16,8 +18,6 @@ use crate::game::{ChooseSomething, PopupMsg, PromptInput, Transition};
use crate::helpers::ID;
use crate::load::MapLoader;
use crate::sandbox::GameplayMode;
use map_gui::options::OptionsPanel;
use map_gui::render::{calculate_corners, DrawOptions};
mod blocked_by;
mod floodfill;

View File

@ -7,6 +7,7 @@ use aabb_quadtree::QuadTree;
use abstutil::{prettyprint_usize, Parallelism, Timer};
use geom::{Circle, Distance, PolyLine, Polygon, Pt2D, Ring};
use kml::{ExtraShape, ExtraShapes};
use map_gui::colors::ColorScheme;
use map_model::BuildingID;
use widgetry::{
lctrl, Btn, Choice, Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key,
@ -15,7 +16,6 @@ use widgetry::{
use crate::app::App;
use crate::game::{ChooseSomething, PopupMsg, Transition};
use map_gui::colors::ColorScheme;
pub struct ViewKML {
panel: Panel,

View File

@ -14,7 +14,6 @@ use crate::game::{ChooseSomething, Transition};
use crate::helpers::nice_map_name;
mod collisions;
pub mod controls;
mod destinations;
pub mod fifteen_min;
mod kml;

View File

@ -2,6 +2,8 @@ use std::collections::BTreeSet;
use abstutil::{prettyprint_usize, Counter};
use geom::ArrowCap;
use map_gui::options::OptionsPanel;
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
use map_model::osm;
use widgetry::{
lctrl, Btn, Checkbox, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx,
@ -14,8 +16,6 @@ use crate::common::{CityPicker, Minimap, Navigator};
use crate::game::{PopupMsg, Transition};
use crate::helpers::{nice_map_name, open_browser, ID};
use crate::sandbox::TurnExplorer;
use map_gui::options::OptionsPanel;
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
pub struct Viewer {
top_panel: Panel,

View File

@ -1,6 +1,7 @@
use serde::{Deserialize, Serialize};
use geom::{Distance, LonLat, PolyLine, Polygon, Pt2D, Ring};
use map_gui::render::DrawOptions;
use widgetry::{
lctrl, Btn, Choice, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, Outcome, Panel, RewriteColor, State, Text, VerticalAlignment,
@ -10,7 +11,6 @@ use widgetry::{
use crate::app::{App, ShowEverything};
use crate::common::CommonState;
use crate::game::{ChooseSomething, PromptInput, Transition};
use map_gui::render::DrawOptions;
// TODO This is a really great example of things that widgetry ought to make easier. Maybe a radio
// button-ish thing to start?

View File

@ -1,6 +1,7 @@
use std::collections::BTreeSet;
use geom::ArrowCap;
use map_gui::render::{DrawOptions, DrawUberTurnGroup, BIG_ARROW_THICKNESS};
use map_model::{IntersectionCluster, IntersectionID};
use widgetry::{
Btn, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Outcome, Panel,
@ -9,7 +10,6 @@ use widgetry::{
use crate::app::{App, ShowEverything};
use crate::game::Transition;
use map_gui::render::{DrawOptions, DrawUberTurnGroup, BIG_ARROW_THICKNESS};
pub struct ClusterTrafficSignalEditor {
panel: Panel,

View File

@ -1,3 +1,4 @@
use map_gui::render::Renderable;
use map_model::{EditCmd, LaneID, LaneType, Map};
use widgetry::{
Btn, Choice, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State,
@ -13,7 +14,6 @@ use crate::edit::{
use crate::game::Transition;
use crate::helpers::ID;
use crate::sandbox::GameplayMode;
use map_gui::render::Renderable;
pub struct LaneEditor {
l: LaneID,

View File

@ -4,6 +4,8 @@ use maplit::btreeset;
use abstutil::{prettyprint_usize, Timer};
use geom::Speed;
use map_gui::options::OptionsPanel;
use map_gui::render::DrawMap;
use map_model::{EditCmd, IntersectionID, LaneID, LaneType, MapEdits};
use widgetry::{
lctrl, Btn, Choice, Color, Drawable, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Menu,
@ -22,8 +24,6 @@ use crate::debug::DebugMode;
use crate::game::{ChooseSomething, PopupMsg, Transition};
use crate::helpers::{grey_out_map, ID};
use crate::sandbox::{GameplayMode, SandboxMode, TimeWarpScreen};
use map_gui::options::OptionsPanel;
use map_gui::render::DrawMap;
mod bulk;
mod cluster_traffic_signals;

View File

@ -4,6 +4,7 @@ use maplit::btreeset;
use abstutil::Timer;
use geom::Polygon;
use map_gui::render::DrawIntersection;
use map_model::{
ControlStopSign, ControlTrafficSignal, EditCmd, EditIntersection, IntersectionID, RoadID,
};
@ -17,7 +18,6 @@ use crate::common::CommonState;
use crate::edit::{apply_map_edits, check_sidewalk_connectivity, TrafficSignalEditor};
use crate::game::Transition;
use crate::sandbox::GameplayMode;
use map_gui::render::DrawIntersection;
// TODO For now, individual turns can't be manipulated. Banning turns could be useful, but I'm not
// sure what to do about the player orphaning a section of the map.

View File

@ -2,6 +2,8 @@ use std::collections::{BTreeSet, VecDeque};
use abstutil::Timer;
use geom::{Distance, Duration, Line, Polygon, Pt2D};
use map_gui::options::TrafficSignalStyle;
use map_gui::render::{traffic_signal, DrawMovement, DrawOptions};
use map_model::{
ControlTrafficSignal, EditCmd, EditIntersection, IntersectionID, MovementID, PhaseType, Stage,
TurnPriority,
@ -17,8 +19,6 @@ use crate::common::{CommonState, Warping};
use crate::edit::{apply_map_edits, ConfirmDiscard};
use crate::game::{PopupMsg, Transition};
use crate::sandbox::GameplayMode;
use map_gui::options::TrafficSignalStyle;
use map_gui::render::{traffic_signal, DrawMovement, DrawOptions};
mod edits;
mod offsets;

View File

@ -1,13 +1,13 @@
use std::collections::BTreeMap;
use geom::{Angle, Circle, Distance, Speed, Time};
use map_gui::render::DrawPedestrian;
use map_model::{BuildingID, LaneID, OffstreetParking, Traversable, SIDEWALK_THICKNESS};
use sim::{DrawPedestrianInput, PedestrianID, PersonID, TripMode, TripResult};
use widgetry::{Btn, Color, EventCtx, Line, Text, TextExt, Widget};
use crate::app::App;
use crate::info::{header_btns, make_table, make_tabs, Details, Tab};
use map_gui::render::DrawPedestrian;
pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID) -> Vec<Widget> {
let mut rows = header(ctx, app, details, id, Tab::BldgInfo(id));

View File

@ -2,6 +2,8 @@ use std::collections::{BTreeMap, BTreeSet};
use abstutil::prettyprint_usize;
use geom::{ArrowCap, Distance, Duration, PolyLine, Polygon, Time};
use map_gui::options::TrafficSignalStyle;
use map_gui::render::traffic_signal::draw_signal_stage;
use map_model::{IntersectionID, IntersectionType, PhaseType};
use sim::AgentType;
use widgetry::{
@ -12,8 +14,6 @@ use widgetry::{
use crate::app::App;
use crate::helpers::color_for_agent_type;
use crate::info::{header_btns, make_tabs, throughput, DataOptions, Details, Tab};
use map_gui::options::TrafficSignalStyle;
use map_gui::render::traffic_signal::draw_signal_stage;
pub fn info(ctx: &EventCtx, app: &App, details: &mut Details, id: IntersectionID) -> Vec<Widget> {
let mut rows = header(ctx, app, details, id, Tab::IntersectionInfo(id));

View File

@ -2,6 +2,7 @@ use std::collections::BTreeSet;
use abstutil::{prettyprint_usize, Counter, Parallelism};
use geom::{Circle, Distance, Duration, Pt2D, Time};
use map_gui::render::unzoomed_agent_radius;
use map_model::{
BuildingID, Map, OffstreetParking, ParkingLotID, PathConstraints, PathRequest, RoadID,
};
@ -14,7 +15,6 @@ use widgetry::{
use crate::app::App;
use crate::common::{ColorLegend, ColorNetwork};
use crate::layer::{Layer, LayerOutcome};
use map_gui::render::unzoomed_agent_radius;
pub struct Occupancy {
time: Time,

View File

@ -4,6 +4,7 @@ use maplit::btreeset;
use abstutil::{prettyprint_usize, Counter};
use geom::{Circle, Distance, Duration, Polygon, Pt2D, Time};
use map_gui::render::unzoomed_agent_radius;
use map_model::{IntersectionID, Map, Traversable};
use sim::VehicleType;
use widgetry::{
@ -15,7 +16,6 @@ use crate::app::App;
use crate::common::{ColorLegend, ColorNetwork, DivergingScale};
use crate::helpers::ID;
use crate::layer::{Layer, LayerOutcome};
use map_gui::render::unzoomed_agent_radius;
pub struct Backpressure {
time: Time,

View File

@ -2,13 +2,13 @@
extern crate log;
use abstutil::CmdArgs;
use map_gui::options::Options;
use sim::SimFlags;
use widgetry::{EventCtx, State};
use crate::app::{App, Flags};
use crate::pregame::TitleScreen;
use crate::sandbox::{GameplayMode, SandboxMode};
use map_gui::options::Options;
mod app;
mod challenges;
@ -111,7 +111,6 @@ pub fn main(mut args: CmdArgs) {
let start_with_edits = args.optional("--edits");
let osm_viewer = args.enabled("--osm");
let fifteen_min = args.enabled("--15min");
let experiment = args.enabled("--experiment");
args.done();
@ -124,7 +123,6 @@ pub fn main(mut args: CmdArgs) {
mode,
osm_viewer,
fifteen_min,
experiment,
)
});
}
@ -137,14 +135,12 @@ fn setup_app(
maybe_mode: Option<GameplayMode>,
osm_viewer: bool,
fifteen_min: bool,
experiment: bool,
) -> (App, Vec<Box<dyn State<App>>>) {
let title = !opts.dev
&& !flags.sim_flags.load.contains("player/save")
&& !flags.sim_flags.load.contains("/scenarios/")
&& !osm_viewer
&& !fifteen_min
&& !experiment
&& maybe_mode.is_none();
let mut app = App::new(flags, opts, ctx, title);
@ -188,8 +184,6 @@ fn setup_app(
vec![crate::devtools::fifteen_min::Viewer::random_start(
ctx, &app,
)]
} else if experiment {
vec![crate::devtools::controls::Experiment::new(ctx)]
} else {
let mode = maybe_mode
.unwrap_or_else(|| GameplayMode::Freeform(app.primary.map.get_name().clone()));

View File

@ -2,6 +2,7 @@ use std::collections::HashMap;
use abstutil::{prettyprint_usize, Counter, Parallelism, Timer};
use geom::{ArrowCap, Distance, Duration, Polygon, Time};
use map_gui::render::DrawOptions;
use map_model::{ControlTrafficSignal, IntersectionID, MovementID, PathStep, TurnType};
use sim::TripEndpoint;
use widgetry::{
@ -13,7 +14,6 @@ use crate::app::{App, ShowEverything};
use crate::common::CommonState;
use crate::game::Transition;
use crate::helpers::ID;
use map_gui::render::DrawOptions;
pub struct TrafficSignalDemand {
panel: Panel,

View File

@ -1,6 +1,7 @@
use std::collections::BTreeSet;
use geom::{ArrowCap, Distance, Time};
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
use map_model::{IntersectionID, LaneID, TurnType};
use sim::AgentID;
use widgetry::{
@ -12,7 +13,6 @@ use crate::app::{App, ShowEverything};
use crate::common::{ColorLegend, CommonState};
use crate::game::Transition;
use crate::helpers::ID;
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
/// Draws a preview of the path for the agent under the mouse cursor.
pub struct RoutePreview {

View File

@ -2,6 +2,7 @@ use instant::Instant;
use abstutil::prettyprint_usize;
use geom::{Duration, Polygon, Pt2D, Ring, Time};
use map_gui::render::DrawOptions;
use widgetry::{
Btn, Checkbox, Choice, Color, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome,
Panel, Slider, State, Text, UpdateType, Widget,
@ -12,7 +13,6 @@ use crate::common::Warping;
use crate::game::{PopupMsg, Transition};
use crate::helpers::{grey_out_map, ID};
use crate::sandbox::{GameplayMode, SandboxMode};
use map_gui::render::DrawOptions;
// TODO Text entry would be great
pub struct JumpToTime {

View File

@ -1,6 +1,7 @@
use std::collections::BTreeSet;
use geom::ArrowCap;
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
use map_model::{IntersectionCluster, IntersectionID, PathConstraints};
use widgetry::{
Btn, Checkbox, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, GfxCtx,
@ -13,7 +14,6 @@ use crate::common::CommonState;
use crate::edit::ClusterTrafficSignalEditor;
use crate::game::{PopupMsg, Transition};
use crate::helpers::ID;
use map_gui::render::{DrawOptions, BIG_ARROW_THICKNESS};
pub struct UberTurnPicker {
members: BTreeSet<IntersectionID>,

View File

@ -11,4 +11,4 @@ colorous = "1.0.3"
geom = { path = "../geom" }
map_model = { path = "../map_model" }
sim = { path = "../sim" }
widgetry = { path = "../widgetry", default-features=false }
widgetry = { path = "../widgetry" }

View File

@ -1,6 +1,16 @@
//! Several distinct tools/applications all share the same general structure for their shared GUI
//! state, based around drawing and interacting with a Map.
use colors::{ColorScheme, ColorSchemeChoice};
use map_model::Map;
use options::Options;
use render::DrawMap;
use sim::Sim;
use widgetry::{EventCtx, GfxCtx, SharedAppState};
use crate::helpers::ID;
use crate::render::DrawOptions;
pub mod colors;
pub mod common;
pub mod helpers;
@ -11,18 +21,144 @@ pub mod render;
/// have any common widgetry States... although maybe we can instead organize the common state into
/// a struct, and make the trait we pass around just be a getter/setter for this shared struct?
pub trait AppLike {
fn map(&self) -> &map_model::Map;
fn sim(&self) -> &sim::Sim;
fn cs(&self) -> &colors::ColorScheme;
fn draw_map(&self) -> &render::DrawMap;
fn mut_draw_map(&mut self) -> &mut render::DrawMap;
fn opts(&self) -> &options::Options;
fn mut_opts(&mut self) -> &mut options::Options;
fn unzoomed_agents(&self) -> &render::UnzoomedAgents;
fn map(&self) -> &Map;
fn sim(&self) -> &Sim;
fn cs(&self) -> &ColorScheme;
fn mut_cs(&mut self) -> &mut ColorScheme;
fn draw_map(&self) -> &DrawMap;
fn mut_draw_map(&mut self) -> &mut DrawMap;
fn opts(&self) -> &Options;
fn mut_opts(&mut self) -> &mut Options;
/// Change the color scheme. Idempotent. Return true if there was a change.
fn change_color_scheme(
&mut self,
ctx: &mut widgetry::EventCtx,
cs: colors::ColorSchemeChoice,
) -> bool;
fn change_color_scheme(&mut self, ctx: &mut EventCtx, cs: ColorSchemeChoice) -> bool {
if self.opts().color_scheme == cs {
return false;
}
self.mut_opts().color_scheme = cs;
*self.mut_cs() = ColorScheme::new(ctx, self.opts().color_scheme);
ctx.loading_screen("rerendering map colors", |ctx, timer| {
*self.mut_draw_map() = DrawMap::new(self.map(), self.opts(), self.cs(), ctx, timer);
});
true
}
}
/// Simple app state that just renders a map. Deliberately not sharing the more complicated
/// implementation from the game crate; that handles way more stuff other apps don't need, like
/// agents.
pub struct SimpleApp {
pub map: Map,
pub draw_map: DrawMap,
pub cs: ColorScheme,
pub opts: Options,
}
impl SimpleApp {
pub fn new(ctx: &mut EventCtx) -> SimpleApp {
ctx.loading_screen("load map", |ctx, mut timer| {
let opts = Options::default();
let cs = ColorScheme::new(ctx, opts.color_scheme);
let map = Map::new(abstutil::MapName::seattle("montlake").path(), &mut timer);
let draw_map = DrawMap::new(&map, &opts, &cs, ctx, timer);
// TODO Should we refactor the whole camera state / initial focusing thing?
SimpleApp {
map,
draw_map,
cs,
opts,
}
})
}
fn draw_unzoomed(&self, g: &mut GfxCtx) {
g.redraw(&self.draw_map.draw_all_areas);
g.redraw(&self.draw_map.draw_all_unzoomed_parking_lots);
g.redraw(&self.draw_map.draw_all_unzoomed_roads_and_intersections);
g.redraw(&self.draw_map.draw_all_buildings);
// Not the building paths
}
fn draw_zoomed(&self, g: &mut GfxCtx, opts: DrawOptions) {
let objects = self
.draw_map
.get_renderables_back_to_front(g.get_screen_bounds(), &self.map);
let mut drawn_all_buildings = false;
let mut drawn_all_areas = false;
for obj in objects {
obj.draw(g, self, &opts);
match obj.get_id() {
ID::Building(_) => {
if !drawn_all_buildings {
if opts.show_building_paths {
g.redraw(&self.draw_map.draw_all_building_paths);
}
g.redraw(&self.draw_map.draw_all_buildings);
g.redraw(&self.draw_map.draw_all_building_outlines);
drawn_all_buildings = true;
}
}
ID::Area(_) => {
if !drawn_all_areas {
g.redraw(&self.draw_map.draw_all_areas);
drawn_all_areas = true;
}
}
_ => {}
};
}
}
}
impl AppLike for SimpleApp {
#[inline]
fn map(&self) -> &Map {
&self.map
}
#[inline]
fn sim(&self) -> &Sim {
unreachable!()
}
#[inline]
fn cs(&self) -> &ColorScheme {
&self.cs
}
#[inline]
fn mut_cs(&mut self) -> &mut ColorScheme {
&mut self.cs
}
#[inline]
fn draw_map(&self) -> &DrawMap {
&self.draw_map
}
#[inline]
fn mut_draw_map(&mut self) -> &mut DrawMap {
&mut self.draw_map
}
#[inline]
fn opts(&self) -> &Options {
&self.opts
}
#[inline]
fn mut_opts(&mut self) -> &mut Options {
&mut self.opts
}
}
impl SharedAppState for SimpleApp {
fn draw_default(&self, g: &mut GfxCtx) {
g.clear(self.cs.void_background);
g.redraw(&self.draw_map.boundary_polygon);
if g.canvas.cam_zoom < self.opts.min_zoom_for_detail {
self.draw_unzoomed(g);
} else {
self.draw_zoomed(g, DrawOptions::new());
}
}
}

View File

@ -8,11 +8,11 @@ use map_model::{Map, Traversable};
use sim::{AgentID, Sim, UnzoomedAgent, VehicleType};
use widgetry::{Checkbox, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Panel, Prerender, Widget};
use crate::app::App;
use crate::colors::ColorScheme;
use crate::render::{
draw_vehicle, unzoomed_agent_radius, DrawPedCrowd, DrawPedestrian, Renderable,
};
use crate::AppLike;
pub struct AgentCache {
/// This is controlled almost entirely by the minimap panel. It has no meaning in edit mode.
@ -84,9 +84,9 @@ impl AgentCache {
pub fn calculate_unzoomed_agents<P: AsRef<Prerender>>(
&mut self,
prerender: &mut P,
app: &App,
app: &dyn AppLike,
) -> &QuadTree<AgentID> {
let now = app.primary.sim.time();
let now = app.sim().time();
let mut recalc = true;
if let Some((time, ref orig_agents, _, _)) = self.unzoomed {
if now == time && self.unzoomed_agents == orig_agents.clone() {
@ -96,7 +96,7 @@ impl AgentCache {
if recalc {
let mut batch = GeomBatch::new();
let mut quadtree = QuadTree::default(app.primary.map.get_bounds().as_bbox());
let mut quadtree = QuadTree::default(app.map().get_bounds().as_bbox());
// It's quite silly to produce triangles for the same circle over and over again. ;)
let car_circle = Circle::new(
Pt2D::new(0.0, 0.0),
@ -106,7 +106,7 @@ impl AgentCache {
let ped_circle =
Circle::new(Pt2D::new(0.0, 0.0), unzoomed_agent_radius(None)).to_polygon();
for agent in app.primary.sim.get_unzoomed_agents(&app.primary.map) {
for agent in app.sim().get_unzoomed_agents(app.map()) {
if let Some(color) = self.unzoomed_agents.color(&agent) {
let circle = if agent.id.to_vehicle_type().is_some() {
car_circle.translate(agent.pos.x(), agent.pos.y())
@ -126,19 +126,19 @@ impl AgentCache {
&self.unzoomed.as_ref().unwrap().2
}
pub fn draw_unzoomed_agents(&mut self, g: &mut GfxCtx, app: &App) {
pub fn draw_unzoomed_agents(&mut self, g: &mut GfxCtx, app: &dyn AppLike) {
self.calculate_unzoomed_agents(g, app);
g.redraw(&self.unzoomed.as_ref().unwrap().3);
if app.opts.debug_all_agents {
if app.opts().debug_all_agents {
let mut cnt = 0;
for input in app.primary.sim.get_all_draw_cars(&app.primary.map) {
for input in app.sim().get_all_draw_cars(app.map()) {
cnt += 1;
draw_vehicle(input, &app.primary.map, g.prerender, &app.cs);
draw_vehicle(input, app.map(), g.prerender, app.cs());
}
println!(
"At {}, debugged {} cars",
app.primary.sim.time(),
app.sim().time(),
abstutil::prettyprint_usize(cnt)
);
// Pedestrians aren't the ones crashing

View File

@ -313,7 +313,7 @@ impl DrawMap {
agents.get(on).into_iter().find(|r| r.get_id() == id)
}
// Unsorted, unexpanded, raw result.
/// Unsorted, unexpanded, raw result.
pub fn get_matching_objects(&self, bounds: Bounds) -> Vec<ID> {
let mut results: Vec<ID> = Vec::new();
for &(id, _, _) in &self.quadtree.query(bounds.as_bbox()) {
@ -321,4 +321,58 @@ impl DrawMap {
}
results
}
/// A simple variation of the one in game that shows all layers, ignores dynamic agents.
pub fn get_renderables_back_to_front(&self, bounds: Bounds, map: &Map) -> Vec<&dyn Renderable> {
let mut areas: Vec<&dyn Renderable> = Vec::new();
let mut parking_lots: Vec<&dyn Renderable> = Vec::new();
let mut lanes: Vec<&dyn Renderable> = Vec::new();
let mut roads: Vec<&dyn Renderable> = Vec::new();
let mut intersections: Vec<&dyn Renderable> = Vec::new();
let mut buildings: Vec<&dyn Renderable> = Vec::new();
let mut bus_stops: Vec<&dyn Renderable> = Vec::new();
for id in self.get_matching_objects(bounds) {
match id {
ID::Area(id) => areas.push(self.get_a(id)),
ID::Lane(id) => {
lanes.push(self.get_l(id));
for bs in &map.get_l(id).bus_stops {
bus_stops.push(self.get_bs(*bs));
}
}
ID::Road(id) => {
roads.push(self.get_r(id));
}
ID::Intersection(id) => {
intersections.push(self.get_i(id));
}
ID::Building(id) => buildings.push(self.get_b(id)),
ID::ParkingLot(id) => {
parking_lots.push(self.get_pl(id));
}
ID::BusStop(_) | ID::Car(_) | ID::Pedestrian(_) | ID::PedCrowd(_) => {
panic!("{:?} shouldn't be in the quadtree", id)
}
}
}
// From background to foreground Z-order
let mut borrows: Vec<&dyn Renderable> = Vec::new();
borrows.extend(areas);
borrows.extend(parking_lots);
borrows.extend(lanes);
borrows.extend(roads);
borrows.extend(intersections);
borrows.extend(buildings);
borrows.extend(bus_stops);
//borrows.retain(|x| x.get_zorder() <= self.primary.show_zorder);
// This is a stable sort.
borrows.sort_by_key(|x| x.get_zorder());
borrows
}
}