mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-23 08:54:30 +03:00
Prompt the user to use a bus gate when necessary. #965
This commit is contained in:
parent
daf3ed379d
commit
bb389bf003
@ -84,6 +84,12 @@ impl Layers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_bus_routes(&mut self, ctx: &mut EventCtx, cs: &ColorScheme) {
|
||||
self.minimized = false;
|
||||
self.show_bus_routes = true;
|
||||
self.update_panel(ctx, cs);
|
||||
}
|
||||
|
||||
fn update_panel(&mut self, ctx: &mut EventCtx, cs: &ColorScheme) {
|
||||
self.panel = Panel::new_builder(
|
||||
Widget::col(vec![
|
||||
|
@ -3,7 +3,7 @@ use widgetry::tools::open_browser;
|
||||
use widgetry::{lctrl, EventCtx, Key, Line, Text, Transition, Widget};
|
||||
|
||||
use super::{road_name, EditOutcome, Obj};
|
||||
use crate::{after_edit, colors, App, DiagonalFilter, Neighbourhood, RoadFilter};
|
||||
use crate::{after_edit, colors, App, DiagonalFilter, FilterType, Neighbourhood, RoadFilter};
|
||||
|
||||
pub fn widget(ctx: &mut EventCtx) -> Widget {
|
||||
Text::from(Line(
|
||||
@ -84,6 +84,17 @@ pub fn handle_world_outcome(
|
||||
let pt_on_line = road.center_pts.project_pt(cursor_pt);
|
||||
let (distance, _) = road.center_pts.dist_along_of_point(pt_on_line).unwrap();
|
||||
|
||||
// If we have a one-way bus route, the one-way resolver will win and we won't warn
|
||||
// about bus gates. Oh well.
|
||||
if app.session.filter_type != FilterType::BusGate
|
||||
&& !app.map.get_bus_routes_on_road(r).is_empty()
|
||||
{
|
||||
app.session.edits.cancel_empty_edit();
|
||||
return EditOutcome::Transition(Transition::Push(
|
||||
super::ResolveBusGate::new_state(ctx, app, vec![(r, distance)]),
|
||||
));
|
||||
}
|
||||
|
||||
app.session.edits.roads.insert(
|
||||
r,
|
||||
RoadFilter::new_by_user(distance, app.session.filter_type),
|
||||
|
@ -2,7 +2,7 @@ use geom::PolyLine;
|
||||
use widgetry::{EventCtx, Line, Text, Widget};
|
||||
|
||||
use crate::edit::{EditMode, EditOutcome};
|
||||
use crate::{after_edit, App, DiagonalFilter, Neighbourhood, RoadFilter, Transition};
|
||||
use crate::{after_edit, App, DiagonalFilter, FilterType, Neighbourhood, RoadFilter, Transition};
|
||||
|
||||
pub fn widget(ctx: &mut EventCtx) -> Widget {
|
||||
Text::from_all(vec![
|
||||
@ -35,6 +35,7 @@ fn make_filters_along_path(
|
||||
path: PolyLine,
|
||||
) -> Transition {
|
||||
let mut oneways = Vec::new();
|
||||
let mut bus_roads = Vec::new();
|
||||
|
||||
app.session.edits.before_edit();
|
||||
for r in &neighbourhood.orig_perimeter.interior {
|
||||
@ -57,6 +58,14 @@ fn make_filters_along_path(
|
||||
.dist_along_of_point(pt)
|
||||
.map(|pair| pair.0)
|
||||
.unwrap_or(road.center_pts.length() / 2.0);
|
||||
|
||||
if app.session.filter_type != FilterType::BusGate
|
||||
&& !app.map.get_bus_routes_on_road(*r).is_empty()
|
||||
{
|
||||
bus_roads.push((*r, dist));
|
||||
continue;
|
||||
}
|
||||
|
||||
app.session
|
||||
.edits
|
||||
.roads
|
||||
@ -71,9 +80,11 @@ fn make_filters_along_path(
|
||||
}
|
||||
after_edit(ctx, app);
|
||||
|
||||
if oneways.is_empty() {
|
||||
Transition::Recreate
|
||||
} else {
|
||||
if !oneways.is_empty() {
|
||||
Transition::Push(super::ResolveOneWayAndFilter::new_state(ctx, oneways))
|
||||
} else if !bus_roads.is_empty() {
|
||||
Transition::Push(super::ResolveBusGate::new_state(ctx, app, bus_roads))
|
||||
} else {
|
||||
Transition::Recreate
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ mod freehand_filters;
|
||||
mod one_ways;
|
||||
mod shortcuts;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use geom::Distance;
|
||||
use map_gui::tools::grey_out_map;
|
||||
use map_model::{EditRoad, IntersectionID, Road, RoadID};
|
||||
use street_network::{Direction, LaneSpec};
|
||||
@ -405,3 +408,88 @@ impl State<App> for ResolveOneWayAndFilter {
|
||||
self.panel.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
struct ResolveBusGate {
|
||||
panel: Panel,
|
||||
roads: Vec<(RoadID, Distance)>,
|
||||
}
|
||||
|
||||
impl ResolveBusGate {
|
||||
fn new_state(
|
||||
ctx: &mut EventCtx,
|
||||
app: &mut App,
|
||||
roads: Vec<(RoadID, Distance)>,
|
||||
) -> Box<dyn State<App>> {
|
||||
app.session.layers.show_bus_routes(ctx, &app.cs);
|
||||
|
||||
let mut txt = Text::new();
|
||||
txt.add_line(Line("Warning").small_heading());
|
||||
txt.add_line("A regular modal filter would impact bus routes here.");
|
||||
txt.add_line("A bus gate uses signage and camera enforcement to only allow buses");
|
||||
// TODO Enable after regenerating maps with correct route names
|
||||
if false {
|
||||
txt.add_line("");
|
||||
txt.add_line("The following bus routes cross this road:");
|
||||
|
||||
let mut routes = BTreeSet::new();
|
||||
for (r, _) in &roads {
|
||||
routes.extend(app.map.get_bus_routes_on_road(*r));
|
||||
}
|
||||
for route in routes {
|
||||
txt.add_line(format!("- {route}"));
|
||||
}
|
||||
}
|
||||
|
||||
let panel = Panel::new_builder(Widget::col(vec![
|
||||
txt.into_widget(ctx),
|
||||
Widget::row(vec![
|
||||
// TODO Just have pictures?
|
||||
ctx.style()
|
||||
.btn_solid
|
||||
.text("Place a regular modal filter here")
|
||||
.build_def(ctx),
|
||||
ctx.style()
|
||||
.btn_solid_primary
|
||||
.text("Place bus gates")
|
||||
.build_def(ctx),
|
||||
]),
|
||||
]))
|
||||
.build(ctx);
|
||||
|
||||
Box::new(Self { panel, roads })
|
||||
}
|
||||
}
|
||||
|
||||
impl State<App> for ResolveBusGate {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
if let Outcome::Clicked(x) = self.panel.event(ctx) {
|
||||
app.session.edits.before_edit();
|
||||
let filter_type = if x == "Place bus gates" {
|
||||
FilterType::BusGate
|
||||
} else {
|
||||
app.session.filter_type
|
||||
};
|
||||
|
||||
for (r, dist) in self.roads.drain(..) {
|
||||
app.session
|
||||
.edits
|
||||
.roads
|
||||
.insert(r, RoadFilter::new_by_user(dist, filter_type));
|
||||
}
|
||||
|
||||
after_edit(ctx, app);
|
||||
|
||||
return Transition::Multi(vec![Transition::Pop, Transition::Recreate]);
|
||||
}
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw_baselayer(&self) -> DrawBaselayer {
|
||||
DrawBaselayer::PreviousState
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
grey_out_map(g, app);
|
||||
self.panel.draw(g);
|
||||
}
|
||||
}
|
||||
|
@ -222,10 +222,10 @@ pub fn extract_osm(
|
||||
}
|
||||
}
|
||||
} else if rel.tags.is("type", "route") && rel.tags.is("route", "bus") {
|
||||
for (role, member) in &rel.members {
|
||||
if let OsmID::Way(w) = member {
|
||||
if role.is_empty() {
|
||||
if let Some(name) = doc.ways[w].tags.get("name") {
|
||||
if let Some(name) = rel.tags.get("name") {
|
||||
for (role, member) in &rel.members {
|
||||
if let OsmID::Way(w) = member {
|
||||
if role.is_empty() {
|
||||
bus_routes_on_roads.insert(*w, name.to_string());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user