mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 06:55:40 +03:00
Draw building driveways per zoomed-in road, rather than as one map-wide batch. Otherwise, every single edit to road width needs to redraw all driveways. This doesn't scale with larger maps!
When zoomed in on just a building but not its road, this means the driveway won't show up until the road is in view. Acceptable trade-off.
This commit is contained in:
parent
628f75f9fb
commit
b3ce53aa5f
@ -141,7 +141,6 @@ impl App {
|
||||
if layers.show_buildings {
|
||||
g.redraw(&draw_map.draw_all_buildings);
|
||||
g.redraw(&draw_map.draw_all_building_outlines);
|
||||
// Not the building driveways
|
||||
}
|
||||
|
||||
// Still show some shape selection when zoomed out.
|
||||
@ -193,9 +192,6 @@ impl App {
|
||||
match obj.get_id() {
|
||||
ID::Building(_) => {
|
||||
if !drawn_all_buildings {
|
||||
if opts.show_building_driveways {
|
||||
g.redraw(&draw_map.draw_all_building_driveways);
|
||||
}
|
||||
g.redraw(&draw_map.draw_all_buildings);
|
||||
g.redraw(&draw_map.draw_all_building_outlines);
|
||||
drawn_all_buildings = true;
|
||||
|
@ -720,13 +720,6 @@ pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {
|
||||
.recreate_intersection(i, &app.primary.map);
|
||||
}
|
||||
|
||||
timer.start("resnap buildings");
|
||||
if effects.resnapped_buildings {
|
||||
app.primary
|
||||
.draw_map
|
||||
.recreate_building_driveways(ctx, &app.primary.map, &app.cs, &app.opts);
|
||||
}
|
||||
timer.stop("resnap buildings");
|
||||
for pl in effects.changed_parking_lots {
|
||||
app.primary.draw_map.get_pl(pl).clear_rendering();
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ pub struct Options {
|
||||
pub min_zoom_for_detail: f64,
|
||||
/// Draw buildings in different perspectives
|
||||
pub camera_angle: CameraAngle,
|
||||
/// Draw building driveways.
|
||||
pub show_building_driveways: bool,
|
||||
|
||||
/// When making a screen recording, enable this option to hide some UI elements
|
||||
pub minimal_controls: bool,
|
||||
@ -80,6 +82,7 @@ impl Options {
|
||||
toggle_day_night_colors: false,
|
||||
min_zoom_for_detail: 4.0,
|
||||
camera_angle: CameraAngle::TopDown,
|
||||
show_building_driveways: true,
|
||||
|
||||
time_increment: Duration::minutes(10),
|
||||
dont_draw_time_warp: false,
|
||||
@ -361,7 +364,6 @@ impl<A: AppLike> State<A> for OptionsPanel {
|
||||
ctx.loading_screen("rerendering buildings", |ctx, timer| {
|
||||
let mut all_buildings = GeomBatch::new();
|
||||
let mut all_building_outlines = GeomBatch::new();
|
||||
let mut all_building_driveways = GeomBatch::new();
|
||||
timer
|
||||
.start_iter("rendering buildings", app.map().all_buildings().len());
|
||||
for b in app.map().all_buildings() {
|
||||
@ -375,18 +377,13 @@ impl<A: AppLike> State<A> for OptionsPanel {
|
||||
&mut all_buildings,
|
||||
&mut all_building_outlines,
|
||||
);
|
||||
DrawBuilding::draw_driveway(
|
||||
b,
|
||||
app.map(),
|
||||
app.cs(),
|
||||
app.opts(),
|
||||
&mut all_building_driveways,
|
||||
);
|
||||
}
|
||||
for r in &mut app.mut_draw_map().roads {
|
||||
r.clear_rendering();
|
||||
}
|
||||
|
||||
timer.start("upload geometry");
|
||||
app.mut_draw_map().draw_all_buildings = all_buildings.upload(ctx);
|
||||
app.mut_draw_map().draw_all_building_driveways =
|
||||
all_building_driveways.upload(ctx);
|
||||
app.mut_draw_map().draw_all_building_outlines =
|
||||
all_building_outlines.upload(ctx);
|
||||
timer.stop("upload geometry");
|
||||
@ -411,7 +408,11 @@ impl<A: AppLike> State<A> for OptionsPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// Be careful -- there are some options not exposed by this panel, but per app.
|
||||
let show_building_driveways = opts.show_building_driveways;
|
||||
opts.show_building_driveways = true;
|
||||
abstio::write_json(abstio::path_player("settings.json"), &opts);
|
||||
opts.show_building_driveways = show_building_driveways;
|
||||
*app.mut_opts() = opts;
|
||||
|
||||
return widgetry::Transition::Pop;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use geom::{Angle, Distance, Line, Polygon, Pt2D, Ring};
|
||||
use map_model::{Building, BuildingID, LaneType, Map, OffstreetParking, NORMAL_LANE_THICKNESS};
|
||||
use map_model::{Building, BuildingID, Map, OffstreetParking};
|
||||
use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Text};
|
||||
|
||||
use crate::colors::{ColorScheme, ColorSchemeChoice};
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::options::{CameraAngle, Options};
|
||||
use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
|
||||
use crate::{AppLike, ID};
|
||||
@ -195,41 +195,6 @@ impl DrawBuilding {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_driveway(
|
||||
bldg: &Building,
|
||||
map: &Map,
|
||||
cs: &ColorScheme,
|
||||
opts: &Options,
|
||||
batch: &mut GeomBatch,
|
||||
) {
|
||||
if opts.camera_angle != CameraAngle::Abstract {
|
||||
// Trim the driveway away from the sidewalk's center line, so that it doesn't overlap.
|
||||
// For now, this cleanup is visual; it doesn't belong in the map_model
|
||||
// layer.
|
||||
let orig_pl = &bldg.driveway_geom;
|
||||
let driveway = orig_pl
|
||||
.slice(
|
||||
Distance::ZERO,
|
||||
orig_pl.length() - map.get_l(bldg.sidewalk()).width / 2.0,
|
||||
)
|
||||
.map(|(pl, _)| pl)
|
||||
.unwrap_or_else(|_| orig_pl.clone());
|
||||
if driveway.length() > Distance::meters(0.1) {
|
||||
batch.push(
|
||||
if opts.color_scheme == ColorSchemeChoice::NightMode {
|
||||
Color::hex("#4B4B4B")
|
||||
} else {
|
||||
cs.zoomed_road_surface(
|
||||
LaneType::Sidewalk,
|
||||
map.get_parent(bldg.sidewalk()).get_rank(),
|
||||
)
|
||||
},
|
||||
driveway.make_polygons(NORMAL_LANE_THICKNESS),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_rendering(&mut self) {
|
||||
*self.label.borrow_mut() = None;
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ pub struct DrawMap {
|
||||
pub boundary_polygon: Drawable,
|
||||
pub draw_all_unzoomed_roads_and_intersections: Drawable,
|
||||
pub draw_all_buildings: Drawable,
|
||||
pub draw_all_building_driveways: Drawable,
|
||||
pub draw_all_building_outlines: Drawable,
|
||||
pub draw_all_unzoomed_parking_lots: Drawable,
|
||||
pub draw_all_areas: Drawable,
|
||||
@ -84,7 +83,6 @@ impl DrawMap {
|
||||
let mut buildings: Vec<DrawBuilding> = Vec::new();
|
||||
let mut all_buildings = GeomBatch::new();
|
||||
let mut all_building_outlines = GeomBatch::new();
|
||||
let mut all_building_driveways = GeomBatch::new();
|
||||
timer.start_iter("make DrawBuildings", map.all_buildings().len());
|
||||
for b in map.all_buildings() {
|
||||
timer.next();
|
||||
@ -97,11 +95,9 @@ impl DrawMap {
|
||||
&mut all_buildings,
|
||||
&mut all_building_outlines,
|
||||
));
|
||||
DrawBuilding::draw_driveway(b, map, cs, opts, &mut all_building_driveways);
|
||||
}
|
||||
timer.start("upload all buildings");
|
||||
let draw_all_buildings = all_buildings.upload(ctx);
|
||||
let draw_all_building_driveways = all_building_driveways.upload(ctx);
|
||||
let draw_all_building_outlines = all_building_outlines.upload(ctx);
|
||||
timer.stop("upload all buildings");
|
||||
|
||||
@ -196,7 +192,6 @@ impl DrawMap {
|
||||
boundary_polygon,
|
||||
draw_all_unzoomed_roads_and_intersections,
|
||||
draw_all_buildings,
|
||||
draw_all_building_driveways,
|
||||
draw_all_building_outlines,
|
||||
draw_all_unzoomed_parking_lots,
|
||||
draw_all_areas,
|
||||
@ -436,7 +431,6 @@ impl DrawMap {
|
||||
|
||||
let mut bldgs_batch = GeomBatch::new();
|
||||
let mut outlines_batch = GeomBatch::new();
|
||||
let mut driveways_batch = GeomBatch::new();
|
||||
for b in map.all_buildings() {
|
||||
DrawBuilding::new(
|
||||
ctx,
|
||||
@ -447,9 +441,7 @@ impl DrawMap {
|
||||
&mut bldgs_batch,
|
||||
&mut outlines_batch,
|
||||
);
|
||||
DrawBuilding::draw_driveway(b, map, cs, app.opts(), &mut driveways_batch);
|
||||
}
|
||||
batch.append(driveways_batch);
|
||||
batch.append(bldgs_batch);
|
||||
batch.append(outlines_batch);
|
||||
|
||||
@ -505,20 +497,6 @@ impl DrawMap {
|
||||
self.roads[road.id.0] = draw;
|
||||
}
|
||||
|
||||
pub fn recreate_building_driveways(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
map: &Map,
|
||||
cs: &ColorScheme,
|
||||
opts: &Options,
|
||||
) {
|
||||
let mut batch = GeomBatch::new();
|
||||
for b in map.all_buildings() {
|
||||
DrawBuilding::draw_driveway(b, map, cs, opts, &mut batch);
|
||||
}
|
||||
self.draw_all_building_driveways = ctx.upload(batch);
|
||||
}
|
||||
|
||||
pub fn free_memory(&mut self) {
|
||||
// Clear the lazily evaluated zoomed-in details
|
||||
for r in &mut self.roads {
|
||||
|
@ -78,8 +78,6 @@ pub struct DrawOptions {
|
||||
pub suppress_traffic_signal_details: Vec<IntersectionID>,
|
||||
/// Label every building.
|
||||
pub label_buildings: bool,
|
||||
/// Draw building driveways.
|
||||
pub show_building_driveways: bool,
|
||||
}
|
||||
|
||||
impl DrawOptions {
|
||||
@ -88,7 +86,6 @@ impl DrawOptions {
|
||||
DrawOptions {
|
||||
suppress_traffic_signal_details: Vec::new(),
|
||||
label_buildings: false,
|
||||
show_building_driveways: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use abstutil::MultiMap;
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
use map_model::{LaneType, Map, Road, RoadID};
|
||||
use widgetry::{Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
|
||||
use map_model::{Building, BuildingID, LaneType, Map, Road, RoadID, NORMAL_LANE_THICKNESS};
|
||||
use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
|
||||
|
||||
use crate::colors::ColorSchemeChoice;
|
||||
use crate::options::CameraAngle;
|
||||
use crate::render::{DrawOptions, Renderable};
|
||||
use crate::{AppLike, ID};
|
||||
|
||||
@ -104,6 +107,13 @@ impl DrawRoad {
|
||||
}
|
||||
}
|
||||
|
||||
// Driveways of connected buildings. These are grouped by road to limit what has to be
|
||||
// recalculated when road edits cause buildings to re-snap.
|
||||
// TODO Cache road_to_buildings in app... or Map?
|
||||
for b in road_to_buildings(app).get(self.id) {
|
||||
draw_building_driveway(app, app.map().get_b(*b), &mut batch);
|
||||
}
|
||||
|
||||
batch
|
||||
}
|
||||
|
||||
@ -138,3 +148,42 @@ impl Renderable for DrawRoad {
|
||||
self.zorder
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_building_driveway(app: &dyn AppLike, bldg: &Building, batch: &mut GeomBatch) {
|
||||
if app.opts().camera_angle == CameraAngle::Abstract || !app.opts().show_building_driveways {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trim the driveway away from the sidewalk's center line, so that it doesn't overlap. For
|
||||
// now, this cleanup is visual; it doesn't belong in the map_model layer.
|
||||
let orig_pl = &bldg.driveway_geom;
|
||||
let driveway = orig_pl
|
||||
.slice(
|
||||
Distance::ZERO,
|
||||
orig_pl.length() - app.map().get_l(bldg.sidewalk()).width / 2.0,
|
||||
)
|
||||
.map(|(pl, _)| pl)
|
||||
.unwrap_or_else(|_| orig_pl.clone());
|
||||
if driveway.length() > Distance::meters(0.1) {
|
||||
batch.push(
|
||||
if app.opts().color_scheme == ColorSchemeChoice::NightMode {
|
||||
Color::hex("#4B4B4B")
|
||||
} else {
|
||||
app.cs().zoomed_road_surface(
|
||||
LaneType::Sidewalk,
|
||||
app.map().get_parent(bldg.sidewalk()).get_rank(),
|
||||
)
|
||||
},
|
||||
driveway.make_polygons(NORMAL_LANE_THICKNESS),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn road_to_buildings(app: &dyn AppLike) -> MultiMap<RoadID, BuildingID> {
|
||||
let map = app.map();
|
||||
let mut mapping = MultiMap::new();
|
||||
for b in map.all_buildings() {
|
||||
mapping.insert(map.get_l(b.sidewalk_pos.lane()).parent, b.id);
|
||||
}
|
||||
mapping
|
||||
}
|
||||
|
@ -132,9 +132,6 @@ impl<T: 'static> SimpleApp<T> {
|
||||
match obj.get_id() {
|
||||
ID::Building(_) => {
|
||||
if !drawn_all_buildings {
|
||||
if opts.show_building_driveways {
|
||||
g.redraw(&self.draw_map.draw_all_building_driveways);
|
||||
}
|
||||
g.redraw(&self.draw_map.draw_all_buildings);
|
||||
g.redraw(&self.draw_map.draw_all_building_outlines);
|
||||
drawn_all_buildings = true;
|
||||
|
@ -139,7 +139,6 @@ pub struct EditEffects {
|
||||
pub changed_intersections: BTreeSet<IntersectionID>,
|
||||
pub added_turns: BTreeSet<TurnID>,
|
||||
pub deleted_turns: BTreeSet<TurnID>,
|
||||
pub resnapped_buildings: bool,
|
||||
pub changed_parking_lots: BTreeSet<ParkingLotID>,
|
||||
}
|
||||
|
||||
@ -516,10 +515,9 @@ fn modify_lanes(map: &mut Map, r: RoadID, lanes_ltr: Vec<LaneSpec>, effects: &mu
|
||||
for b in map.all_buildings() {
|
||||
if modified_lanes.contains(&b.sidewalk()) {
|
||||
recalc_buildings.push(b.id);
|
||||
effects.resnapped_buildings = true;
|
||||
}
|
||||
}
|
||||
fix_building_driveways(map, recalc_buildings);
|
||||
fix_building_driveways(map, recalc_buildings, effects);
|
||||
|
||||
// Same for parking lots
|
||||
let mut recalc_parking_lots = Vec::new();
|
||||
@ -617,7 +615,7 @@ fn recalculate_intersection_polygon(
|
||||
}
|
||||
|
||||
/// Recalculate the driveways of some buildings after map edits.
|
||||
fn fix_building_driveways(map: &mut Map, input: Vec<BuildingID>) {
|
||||
fn fix_building_driveways(map: &mut Map, input: Vec<BuildingID>, effects: &mut EditEffects) {
|
||||
// TODO Copying from make/buildings.rs
|
||||
let mut center_per_bldg: BTreeMap<BuildingID, HashablePt2D> = BTreeMap::new();
|
||||
let mut query: HashSet<HashablePt2D> = HashSet::new();
|
||||
@ -649,6 +647,10 @@ fn fix_building_driveways(map: &mut Map, input: Vec<BuildingID>) {
|
||||
let b = &mut map.buildings[id.0];
|
||||
b.sidewalk_pos = sidewalk_pos;
|
||||
b.driveway_geom = driveway_geom.to_polyline();
|
||||
// We may need to redraw the road that now has this building snapped to it
|
||||
effects
|
||||
.changed_roads
|
||||
.insert(map.get_l(sidewalk_pos.lane()).parent);
|
||||
}
|
||||
None => {
|
||||
// TODO Not sure what to do here yet.
|
||||
@ -776,7 +778,6 @@ impl Map {
|
||||
changed_intersections: BTreeSet::new(),
|
||||
added_turns: BTreeSet::new(),
|
||||
deleted_turns: BTreeSet::new(),
|
||||
resnapped_buildings: false,
|
||||
changed_parking_lots: BTreeSet::new(),
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,8 @@ pub fn main() {
|
||||
}
|
||||
|
||||
pub fn run(mut settings: Settings) {
|
||||
let options = map_gui::options::Options::load_or_default();
|
||||
let mut options = map_gui::options::Options::load_or_default();
|
||||
options.show_building_driveways = false;
|
||||
settings = settings
|
||||
.read_svg(Box::new(abstio::slurp_bytes))
|
||||
.canvas_settings(options.canvas_settings.clone());
|
||||
|
@ -366,9 +366,7 @@ impl State<App> for Viewer {
|
||||
if g.canvas.cam_zoom < app.opts.min_zoom_for_detail {
|
||||
app.draw_unzoomed(g);
|
||||
} else {
|
||||
let mut opts = DrawOptions::new();
|
||||
opts.show_building_driveways = false;
|
||||
app.draw_zoomed(g, opts);
|
||||
app.draw_zoomed(g, DrawOptions::new());
|
||||
}
|
||||
|
||||
self.top_panel.draw(g);
|
||||
|
Loading…
Reference in New Issue
Block a user