Speed up the select boundary UI by caching single blocks

This commit is contained in:
Dustin Carlino 2022-01-15 17:04:31 +00:00
parent c18cc762bb
commit e2621c40f4
2 changed files with 35 additions and 46 deletions

View File

@ -25,7 +25,8 @@ impl widgetry::mapspace::ObjectID for NeighborhoodID {}
#[derive(Clone)]
pub struct Partitioning {
pub neighborhoods: BTreeMap<NeighborhoodID, (Block, Color)>,
// TODO Stash the single blocks here -- they never change
// The single / unmerged blocks never change
pub single_blocks: Vec<Block>,
}
impl Partitioning {
@ -33,19 +34,25 @@ impl Partitioning {
pub fn empty() -> Partitioning {
Partitioning {
neighborhoods: BTreeMap::new(),
single_blocks: Vec::new(),
}
}
pub fn seed_using_heuristics(app: &App, timer: &mut Timer) -> Partitioning {
let map = &app.primary.map;
timer.start("find single blocks");
let mut single_blocks = Perimeter::find_all_single_blocks(map);
// TODO Ew! Expensive! But the merged neighborhoods differ widely from blockfinder if we don't.
single_blocks.retain(|x| x.clone().to_block(map).is_ok());
let mut single_blocks = Vec::new();
let mut single_block_perims = Vec::new();
for perim in Perimeter::find_all_single_blocks(map) {
if let Ok(block) = perim.to_block(map) {
single_block_perims.push(block.perimeter.clone());
single_blocks.push(block);
}
}
timer.stop("find single blocks");
timer.start("partition");
let partitions = Perimeter::partition_by_predicate(single_blocks, |r| {
let partitions = Perimeter::partition_by_predicate(single_block_perims, |r| {
// "Interior" roads of a neighborhood aren't classified as arterial
map.get_r(r).get_rank() == RoadRank::Local
});
@ -81,7 +88,10 @@ impl Partitioning {
let color = COLORS[color_idx % COLORS.len()];
neighborhoods.insert(NeighborhoodID(neighborhoods.len()), (block, color));
}
Partitioning { neighborhoods }
Partitioning {
neighborhoods,
single_blocks,
}
}
pub fn neighborhood_containing(&self, find_block: &Block) -> Option<NeighborhoodID> {

View File

@ -55,49 +55,28 @@ impl SelectBoundary {
orig_partitioning: app.session.partitioning.clone(),
};
ctx.loading_screen("calculate all blocks", |ctx, timer| {
timer.start("find single blocks");
let perimeters = Perimeter::find_all_single_blocks(&app.primary.map);
timer.stop("find single blocks");
let mut blocks = Vec::new();
timer.start_iter("blockify", perimeters.len());
for perimeter in perimeters {
timer.next();
match perimeter.to_block(&app.primary.map) {
Ok(block) => {
blocks.push(block);
}
Err(err) => {
warn!("Failed to make a block from a perimeter: {}", err);
}
}
for (idx, block) in app.session.partitioning.single_blocks.iter().enumerate() {
let id = BlockID(idx);
if let Some(neighborhood) = app.session.partitioning.neighborhood_containing(block) {
state.block_to_neighborhood.insert(id, neighborhood);
} else {
// TODO What happened?
error!(
"Block doesn't belong to any neighborhood?! {:?}",
block.perimeter
);
}
for (idx, block) in blocks.into_iter().enumerate() {
let id = BlockID(idx);
if let Some(neighborhood) = app.session.partitioning.neighborhood_containing(&block)
{
state.block_to_neighborhood.insert(id, neighborhood);
} else {
// TODO What happened?
error!(
"Block doesn't belong to any neighborhood?! {:?}",
block.perimeter
);
}
if initial_boundary.contains(&block.perimeter) {
state.selected.insert(id);
}
state.blocks.insert(id, block);
if initial_boundary.contains(&block.perimeter) {
state.selected.insert(id);
}
state.frontier = calculate_frontier(&initial_boundary, &state.blocks);
state.blocks.insert(id, block.clone());
}
state.frontier = calculate_frontier(&initial_boundary, &state.blocks);
// Fill out the world initially
for id in state.blocks.keys().cloned().collect::<Vec<_>>() {
state.add_block(ctx, app, id);
}
});
// Fill out the world initially
for id in state.blocks.keys().cloned().collect::<Vec<_>>() {
state.add_block(ctx, app, id);
}
state.redraw_outline(ctx, app, initial_boundary);
state.world.initialize_hover(ctx);