Let the user place filters at non-4 way intersections; it's equivalent to placing a filter along the edge of adjoining roads. #862

This commit is contained in:
Dustin Carlino 2022-03-04 15:10:47 +00:00
parent 5fcaf7b657
commit 559adbe01d
2 changed files with 49 additions and 36 deletions

View File

@ -11,7 +11,7 @@ use widgetry::mapspace::{DrawUnzoomedShapes, ToggleZoomed};
use widgetry::{Color, EventCtx, GeomBatch, GfxCtx};
pub use self::existing::transform_existing_filters;
use crate::App;
use crate::{after_edit, App};
/// Stored in App session state. Before making any changes, call `before_edit`.
#[derive(Clone, Default, Serialize, Deserialize)]
@ -155,19 +155,57 @@ impl ModalFilters {
}
impl DiagonalFilter {
/// Find all possible diagonal filters at an intersection
pub fn filters_for(app: &App, i: IntersectionID) -> Vec<DiagonalFilter> {
pub fn cycle_through_alternatives(ctx: &EventCtx, app: &mut App, i: IntersectionID) {
app.session.modal_filters.before_edit();
let map = &app.map;
let roads = map.get_i(i).get_roads_sorted_by_incoming_angle(map);
// TODO Handle >4-ways
if roads.len() != 4 {
return Vec::new();
if roads.len() == 4 {
// 4-way intersections are the only place where true diagonal filters can be placed
let alt1 = DiagonalFilter::new(map, i, roads[0], roads[1]);
let alt2 = DiagonalFilter::new(map, i, roads[1], roads[2]);
match app.session.modal_filters.intersections.get(&i) {
Some(prev) => {
if prev == &alt1 {
app.session.modal_filters.intersections.insert(i, alt2);
} else if prev == &alt2 {
app.session.modal_filters.intersections.remove(&i);
} else {
unreachable!()
}
}
None => {
app.session.modal_filters.intersections.insert(i, alt1);
}
}
} else if roads.len() > 2 {
// Diagonal filters elsewhere don't really make sense. They're equivalent to filtering
// one road. Just cycle through those.
let mut add_filter_to = None;
if let Some(idx) = roads
.iter()
.position(|r| app.session.modal_filters.roads.contains_key(r))
{
app.session.modal_filters.roads.remove(&roads[idx]);
if idx != roads.len() - 1 {
add_filter_to = Some(roads[idx + 1]);
}
} else {
add_filter_to = Some(roads[0]);
}
if let Some(r) = add_filter_to {
let road = map.get_r(r);
let dist = if i == road.src_i {
Distance::ZERO
} else {
road.length()
};
app.session.modal_filters.roads.insert(r, dist);
}
}
vec![
DiagonalFilter::new(map, i, roads[0], roads[1]),
DiagonalFilter::new(map, i, roads[1], roads[2]),
]
after_edit(ctx, app);
}
fn new(map: &Map, i: IntersectionID, r1: RoadID, r2: RoadID) -> DiagonalFilter {

View File

@ -226,32 +226,7 @@ pub fn handle_world_outcome(
true
}
WorldOutcome::ClickedObject(FilterableObj::InteriorIntersection(i)) => {
if map.get_i(i).roads.len() != 4 {
// Misleading. Nothing changes, but we'll "fall through" to other cases without
// this
return true;
}
// Toggle through all possible filters
app.session.modal_filters.before_edit();
let mut all = DiagonalFilter::filters_for(app, i);
if let Some(current) = app.session.modal_filters.intersections.get(&i) {
let idx = all.iter().position(|x| x == current).unwrap();
if idx == all.len() - 1 {
app.session.modal_filters.intersections.remove(&i);
} else {
app.session
.modal_filters
.intersections
.insert(i, all.remove(idx + 1));
}
} else if !all.is_empty() {
app.session
.modal_filters
.intersections
.insert(i, all.remove(0));
}
after_edit(ctx, app);
DiagonalFilter::cycle_through_alternatives(ctx, app, i);
true
}
WorldOutcome::Keypress("debug", FilterableObj::InteriorIntersection(i)) => {