mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
starting a dedicated OSM mapping mode for parking in the main game, not map_editor
This commit is contained in:
parent
c6f34de3d7
commit
d55ebb71ca
159
game/src/devtools/mapping.rs
Normal file
159
game/src/devtools/mapping.rs
Normal file
@ -0,0 +1,159 @@
|
||||
use crate::app::{App, ShowEverything};
|
||||
use crate::common::ColorLegend;
|
||||
use crate::game::{State, Transition};
|
||||
use crate::helpers::ID;
|
||||
use abstutil::prettyprint_usize;
|
||||
use ezgui::{
|
||||
hotkey, Btn, Checkbox, Color, Composite, Drawable, EventCtx, GeomBatch, GfxCtx,
|
||||
HorizontalAlignment, Key, Line, Outcome, TextExt, VerticalAlignment, Widget,
|
||||
};
|
||||
use map_model::{osm, RoadID};
|
||||
use sim::DontDrawAgents;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct ParkingMapper {
|
||||
composite: Composite,
|
||||
draw_layer: Drawable,
|
||||
show_todo: bool,
|
||||
selected: Option<(HashSet<RoadID>, Drawable)>,
|
||||
}
|
||||
|
||||
impl ParkingMapper {
|
||||
pub fn new(ctx: &mut EventCtx, app: &App, show_todo: bool) -> Box<dyn State> {
|
||||
let map = &app.primary.map;
|
||||
|
||||
let color = if show_todo {
|
||||
Color::RED.alpha(0.5)
|
||||
} else {
|
||||
Color::BLUE.alpha(0.5)
|
||||
};
|
||||
let mut batch = GeomBatch::new();
|
||||
let mut done = HashSet::new();
|
||||
let mut todo = HashSet::new();
|
||||
for r in map.all_roads() {
|
||||
if r.osm_tags.contains_key(osm::INFERRED_PARKING) {
|
||||
todo.insert(r.orig_id);
|
||||
if show_todo {
|
||||
batch.push(color, map.get_r(r.id).get_thick_polygon(map).unwrap());
|
||||
}
|
||||
} else {
|
||||
done.insert(r.orig_id);
|
||||
if !show_todo {
|
||||
batch.push(color, map.get_r(r.id).get_thick_polygon(map).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nicer display
|
||||
for i in map.all_intersections() {
|
||||
let is_todo = i
|
||||
.roads
|
||||
.iter()
|
||||
.any(|r| map.get_r(*r).osm_tags.contains_key(osm::INFERRED_PARKING));
|
||||
if show_todo == is_todo {
|
||||
batch.push(color, i.polygon.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(ParkingMapper {
|
||||
draw_layer: ctx.upload(batch),
|
||||
show_todo,
|
||||
composite: Composite::new(
|
||||
Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
Line("Parking mapper")
|
||||
.small_heading()
|
||||
.draw(ctx)
|
||||
.margin_right(10),
|
||||
Btn::text_fg("X")
|
||||
.build_def(ctx, hotkey(Key::Escape))
|
||||
.align_right(),
|
||||
]),
|
||||
format!(
|
||||
"{} / {} ways done",
|
||||
prettyprint_usize(done.len()),
|
||||
prettyprint_usize(done.len() + todo.len())
|
||||
)
|
||||
.draw_text(ctx),
|
||||
Widget::row(vec![
|
||||
Checkbox::text(ctx, "show ways with missing tags", None, show_todo)
|
||||
.margin_right(15),
|
||||
ColorLegend::row(ctx, color, if show_todo { "TODO" } else { "done" }),
|
||||
]),
|
||||
])
|
||||
.padding(10)
|
||||
.bg(app.cs.panel_bg),
|
||||
)
|
||||
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
|
||||
.build(ctx),
|
||||
selected: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl State for ParkingMapper {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
let map = &app.primary.map;
|
||||
|
||||
ctx.canvas_movement();
|
||||
if ctx.redo_mouseover() {
|
||||
let maybe_r = match app.calculate_current_selection(
|
||||
ctx,
|
||||
&DontDrawAgents {},
|
||||
&ShowEverything::new(),
|
||||
false,
|
||||
true,
|
||||
) {
|
||||
Some(ID::Road(r)) => Some(r),
|
||||
Some(ID::Lane(l)) => Some(map.get_l(l).parent),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(id) = maybe_r {
|
||||
if self
|
||||
.selected
|
||||
.as_ref()
|
||||
.map(|(ids, _)| !ids.contains(&id))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
// Select all roads part of this way
|
||||
let way = map.get_r(id).orig_id.osm_way_id;
|
||||
let mut ids = HashSet::new();
|
||||
let mut batch = GeomBatch::new();
|
||||
for r in map.all_roads() {
|
||||
if r.orig_id.osm_way_id == way {
|
||||
ids.insert(r.id);
|
||||
batch.push(Color::GREEN.alpha(0.5), r.get_thick_polygon(map).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
self.selected = Some((ids, ctx.upload(batch)));
|
||||
}
|
||||
} else {
|
||||
self.selected = None;
|
||||
}
|
||||
}
|
||||
|
||||
match self.composite.event(ctx) {
|
||||
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
||||
"X" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
if self.composite.is_checked("show ways with missing tags") != self.show_todo {
|
||||
return Transition::Replace(ParkingMapper::new(ctx, app, !self.show_todo));
|
||||
}
|
||||
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, _: &App) {
|
||||
g.redraw(&self.draw_layer);
|
||||
if let Some((_, ref roads)) = self.selected {
|
||||
g.redraw(roads);
|
||||
}
|
||||
self.composite.draw(g);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
mod blocks;
|
||||
mod mapping;
|
||||
mod polygon;
|
||||
mod scenario;
|
||||
|
||||
@ -22,6 +23,7 @@ impl DevToolsMode {
|
||||
(hotkey(Key::E), "edit a polygon"),
|
||||
(hotkey(Key::P), "draw a polygon"),
|
||||
(hotkey(Key::W), "load scenario"),
|
||||
(hotkey(Key::M), "OSM mapping"),
|
||||
],
|
||||
))
|
||||
.cb("X", Box::new(|_, _| Some(Transition::Pop)))
|
||||
@ -42,6 +44,14 @@ impl DevToolsMode {
|
||||
.cb(
|
||||
"load scenario",
|
||||
Box::new(|_, _| Some(Transition::Push(WizardState::new(Box::new(load_scenario))))),
|
||||
)
|
||||
.cb(
|
||||
"OSM mapping",
|
||||
Box::new(|ctx, app| {
|
||||
Some(Transition::Push(mapping::ParkingMapper::new(
|
||||
ctx, app, true,
|
||||
)))
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ impl UI {
|
||||
}
|
||||
let bounds = model.map.gps_bounds.to_bounds();
|
||||
ctx.canvas.map_dims = (bounds.width(), bounds.height());
|
||||
let mut ui = UI {
|
||||
UI {
|
||||
model,
|
||||
state: State::viewing(),
|
||||
composite: Composite::new(
|
||||
@ -100,33 +100,7 @@ impl UI {
|
||||
info_key_held: false,
|
||||
|
||||
last_id: None,
|
||||
};
|
||||
ui.recount_parking_tags(ctx);
|
||||
ui
|
||||
}
|
||||
|
||||
fn recount_parking_tags(&mut self, ctx: &mut EventCtx) {
|
||||
let mut ways_audited = HashSet::new();
|
||||
let mut ways_missing = HashSet::new();
|
||||
for r in self.model.map.roads.values() {
|
||||
if r.synthetic() {
|
||||
continue;
|
||||
}
|
||||
if r.osm_tags.contains_key(osm::INFERRED_PARKING) {
|
||||
ways_missing.insert(r.osm_tags[osm::OSM_WAY_ID].clone());
|
||||
} else {
|
||||
ways_audited.insert(r.osm_tags[osm::OSM_WAY_ID].clone());
|
||||
}
|
||||
}
|
||||
|
||||
let mut txt = Text::from(Line(format!(
|
||||
"Parking data audited: {} / {} ways",
|
||||
abstutil::prettyprint_usize(ways_audited.len()),
|
||||
abstutil::prettyprint_usize(ways_audited.len() + ways_missing.len())
|
||||
)));
|
||||
txt.add(Line("Hold right Control to show info about objects"));
|
||||
self.composite
|
||||
.replace(ctx, "current info", txt.draw(ctx).named("current info"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,10 +197,6 @@ impl GUI for UI {
|
||||
} else if could_swap && ctx.input.key_pressed(Key::S, "swap lanes") {
|
||||
self.model.swap_lanes(r, ctx.prerender);
|
||||
self.model.world.handle_mouseover(ctx);
|
||||
} else if ctx.input.key_pressed(Key::T, "toggle parking") {
|
||||
self.model.toggle_r_parking(r, ctx.prerender);
|
||||
self.model.world.handle_mouseover(ctx);
|
||||
self.recount_parking_tags(ctx);
|
||||
} else if ctx.input.key_pressed(Key::F, "toggle sidewalks") {
|
||||
self.model.toggle_r_sidewalks(r, ctx.prerender);
|
||||
self.model.world.handle_mouseover(ctx);
|
||||
|
@ -432,76 +432,6 @@ impl Model {
|
||||
self.road_added(id, prerender);
|
||||
}
|
||||
|
||||
pub fn toggle_r_parking(&mut self, some_id: OriginalRoad, prerender: &Prerender) {
|
||||
// Update every road belonging to the way.
|
||||
let osm_id = self.map.roads[&some_id].osm_tags[osm::OSM_WAY_ID].clone();
|
||||
let matching_roads = self
|
||||
.map
|
||||
.roads
|
||||
.iter()
|
||||
.filter_map(|(k, v)| {
|
||||
if v.osm_tags[osm::OSM_WAY_ID] == osm_id {
|
||||
Some(*k)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Verify every road has the same parking tags. Blockface hints might've applied to just
|
||||
// some parts. If this is really true, then the way has to be split. Example is McGraw St.
|
||||
let both = self.map.roads[&some_id]
|
||||
.osm_tags
|
||||
.get(osm::PARKING_BOTH)
|
||||
.cloned();
|
||||
let left = self.map.roads[&some_id]
|
||||
.osm_tags
|
||||
.get(osm::PARKING_LEFT)
|
||||
.cloned();
|
||||
let right = self.map.roads[&some_id]
|
||||
.osm_tags
|
||||
.get(osm::PARKING_RIGHT)
|
||||
.cloned();
|
||||
for r in &matching_roads {
|
||||
let tags = &self.map.roads[r].osm_tags;
|
||||
if tags.get(osm::PARKING_BOTH) != both.as_ref()
|
||||
|| tags.get(osm::PARKING_LEFT) != left.as_ref()
|
||||
|| tags.get(osm::PARKING_RIGHT) != right.as_ref()
|
||||
{
|
||||
println!(
|
||||
"WARNING: {} and {} belong to same way, but have different parking tags!",
|
||||
some_id, r
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for id in matching_roads {
|
||||
self.road_deleted(id);
|
||||
|
||||
let osm_tags = &mut self.map.roads.get_mut(&id).unwrap().osm_tags;
|
||||
osm_tags.remove(osm::INFERRED_PARKING);
|
||||
let yes = "parallel".to_string();
|
||||
let no = "no_parking".to_string();
|
||||
if both.as_ref() == Some(&yes) {
|
||||
osm_tags.insert(osm::PARKING_BOTH.to_string(), no);
|
||||
} else if both.as_ref() == Some(&no) {
|
||||
osm_tags.remove(osm::PARKING_BOTH);
|
||||
osm_tags.insert(osm::PARKING_LEFT.to_string(), yes);
|
||||
osm_tags.insert(osm::PARKING_RIGHT.to_string(), no);
|
||||
} else if left.as_ref() == Some(&yes) {
|
||||
osm_tags.insert(osm::PARKING_LEFT.to_string(), no);
|
||||
osm_tags.insert(osm::PARKING_RIGHT.to_string(), yes);
|
||||
} else if right.as_ref() == Some(&yes) {
|
||||
osm_tags.remove(osm::PARKING_LEFT);
|
||||
osm_tags.remove(osm::PARKING_RIGHT);
|
||||
osm_tags.insert(osm::PARKING_BOTH.to_string(), yes);
|
||||
}
|
||||
|
||||
self.road_added(id, prerender);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Refactor with toggle_r_parking?
|
||||
pub fn toggle_r_sidewalks(&mut self, some_id: OriginalRoad, prerender: &Prerender) {
|
||||
// Update every road belonging to the way.
|
||||
let osm_id = self.map.roads[&some_id].osm_tags[osm::OSM_WAY_ID].clone();
|
||||
@ -527,7 +457,7 @@ impl Model {
|
||||
for r in &matching_roads {
|
||||
if self.map.roads[r].osm_tags.get(osm::SIDEWALK) != value.as_ref() {
|
||||
println!(
|
||||
"WARNING: {} and {} belong to same way, but have different parking tags!",
|
||||
"WARNING: {} and {} belong to same way, but have different sidewalk tags!",
|
||||
some_id, r
|
||||
);
|
||||
}
|
||||
@ -567,8 +497,7 @@ impl Model {
|
||||
let r = &self.map.roads[&id];
|
||||
let unset =
|
||||
r.synthetic() && r.osm_tags.get(osm::NAME) == Some(&"Streety McStreetFace".to_string());
|
||||
let lanes_unknown = r.osm_tags.contains_key(osm::INFERRED_PARKING)
|
||||
|| r.osm_tags.contains_key(osm::INFERRED_SIDEWALKS);
|
||||
let lanes_unknown = r.osm_tags.contains_key(osm::INFERRED_SIDEWALKS);
|
||||
let spec = r.get_spec();
|
||||
let center_pts = PolyLine::new(r.center_points.clone());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user