From 2224dccda931b451a27a1e004e8fef869c01d7b8 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Sun, 11 Jul 2021 13:19:00 -0700 Subject: [PATCH] Add a tool in the main UI to try to merge junctions. #654 It maintains a JSON file of ways to merge that the importer also uses. For maps fast to import, this is the nicest workflow. Unlike map_editor, turns and trimmed roads can also be checked. --- convert_osm/src/extract.rs | 14 +------ game/src/debug/mod.rs | 47 ++++++++++++++++++++++- game/src/debug/select_roads.rs | 18 --------- map_gui/src/load.rs | 9 +++++ map_model/src/make/merge_intersections.rs | 19 +++++++++ 5 files changed, 75 insertions(+), 32 deletions(-) diff --git a/convert_osm/src/extract.rs b/convert_osm/src/extract.rs index f12b628b57..32c22e5b94 100644 --- a/convert_osm/src/extract.rs +++ b/convert_osm/src/extract.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeSet, HashMap}; +use std::collections::HashMap; use osm::{NodeID, OsmID, RelationID, WayID}; @@ -29,18 +29,6 @@ pub struct OsmExtract { pub fn extract_osm(map: &mut RawMap, opts: &Options, timer: &mut Timer) -> OsmExtract { let mut doc = crate::reader::read(&opts.osm_input, &map.gps_bounds, timer).unwrap(); - // Use this to quickly test overrides to some ways before upstreaming in OSM. - if false { - let ways: BTreeSet = abstio::read_json("osm_ways.json".to_string(), timer); - for id in ways { - doc.ways - .get_mut(&id) - .unwrap() - .tags - .insert("junction", "intersection"); - } - } - // TODO Hacks to override OSM data. There's no problem upstream, but we want to accomplish // various things for A/B Street. if let Some(way) = doc.ways.get_mut(&WayID(881403608)) { diff --git a/game/src/debug/mod.rs b/game/src/debug/mod.rs index 5c516938e3..44ba7eac57 100644 --- a/game/src/debug/mod.rs +++ b/game/src/debug/mod.rs @@ -7,8 +7,9 @@ use map_gui::colors::ColorSchemeChoice; use map_gui::load::MapLoader; use map_gui::options::OptionsPanel; use map_gui::render::{calculate_corners, DrawMap, DrawOptions}; -use map_gui::tools::{ChooseSomething, PopupMsg, PromptInput}; +use map_gui::tools::{find_exe, ChooseSomething, PopupMsg, PromptInput, RunCommand}; use map_gui::{AppLike, ID}; +use map_model::raw::OriginalRoad; use map_model::{ osm, ControlTrafficSignal, IntersectionID, PathConstraints, Position, RoadID, NORMAL_LANE_THICKNESS, @@ -156,6 +157,11 @@ impl DebugMode { .btn_outline .text("import color-scheme") .build_def(ctx), + ctx.style() + .btn_outline + .text("undo all merged roads") + .hotkey(lctrl(Key::M)) + .build_def(ctx), ]), Text::from_all(vec![ Line("Hold "), @@ -386,6 +392,14 @@ impl State for DebugMode { DrawMap::new(ctx, &app.primary.map, &app.opts, &app.cs, timer); }); } + "undo all merged roads" => { + if let Err(err) = + std::fs::rename("merge_osm_ways.json", "UNDO_merge_osm_ways.json") + { + warn!("No merged road file? {}", err); + } + return Transition::Push(reimport_map(ctx, app)); + } _ => unreachable!(), }, Outcome::Changed(_) => { @@ -589,6 +603,7 @@ impl ContextualActions for Actions { )); actions.push((Key::C, "export roads".to_string())); actions.push((Key::E, "show equiv_pos".to_string())); + actions.push((Key::M, "merge short segment".to_string())); } ID::Intersection(i) => { actions.push((Key::H, "hide this".to_string())); @@ -781,6 +796,15 @@ impl ContextualActions for Actions { } })) } + (ID::Lane(l), "merge short segment") => { + let mut timer = Timer::throwaway(); + let mut ways: Vec = + abstio::maybe_read_json("merge_osm_ways.json".to_string(), &mut timer) + .unwrap_or_else(|_| Vec::new()); + ways.push(app.primary.map.get_parent(l).orig_id); + abstio::write_json("merge_osm_ways.json".to_string(), &ways); + Transition::Push(reimport_map(ctx, app)) + } (ID::Area(a), "debug area geometry") => { let pts = &app.primary.map.get_a(a).polygon.points(); let center = if pts[0] == *pts.last().unwrap() { @@ -1035,3 +1059,24 @@ fn draw_arterial_crosswalks(ctx: &mut EventCtx, app: &App) -> Drawable { } ctx.upload(batch) } + +fn reimport_map(ctx: &mut EventCtx, app: &App) -> Box> { + RunCommand::new_state( + ctx, + app, + vec![ + find_exe("importer"), + "--map".to_string(), + app.primary.map.get_name().map.clone(), + format!("--city={}", app.primary.map.get_name().city.to_path()), + "--skip_ch".to_string(), + ], + Box::new(|ctx, app, _, _| { + Transition::Push(MapLoader::force_reload( + ctx, + app.primary.map.get_name().clone(), + Box::new(|_, _| Transition::Pop), + )) + }), + ) +} diff --git a/game/src/debug/select_roads.rs b/game/src/debug/select_roads.rs index 3bdd3550f2..96e8b4cf8b 100644 --- a/game/src/debug/select_roads.rs +++ b/game/src/debug/select_roads.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeSet; - use maplit::btreeset; use map_gui::tools::PopupMsg; @@ -40,10 +38,6 @@ fn make_select_panel(ctx: &mut EventCtx, selector: &RoadSelector) -> Panel { .btn_outline .text("export one road to Streetmix") .build_def(ctx), - ctx.style() - .btn_outline - .text("export list of roads") - .build_def(ctx), ctx.style().btn_close_widget(ctx), ]) .evenly_spaced(), @@ -86,18 +80,6 @@ impl State for BulkSelect { )], )); } - "export list of roads" => { - let mut osm_ids: BTreeSet = BTreeSet::new(); - for r in &self.selector.roads { - osm_ids.insert(app.primary.map.get_r(*r).orig_id.osm_way_id); - } - abstio::write_json("osm_ways.json".to_string(), &osm_ids); - return Transition::Push(PopupMsg::new_state( - ctx, - "List of roads exported", - vec!["Wrote osm_ways.json"], - )); - } x => { if self.selector.event(ctx, app, Some(x)) { self.panel = make_select_panel(ctx, &self.selector); diff --git a/map_gui/src/load.rs b/map_gui/src/load.rs index b803205578..f0f5191d3b 100644 --- a/map_gui/src/load.rs +++ b/map_gui/src/load.rs @@ -40,6 +40,15 @@ impl MapLoader { }); } + MapLoader::force_reload(ctx, name, on_load) + } + + /// Even if the current map name matches, still reload. + pub fn force_reload( + ctx: &mut EventCtx, + name: MapName, + on_load: Box Transition>, + ) -> Box> { // TODO Generalize this more, maybe with some kind of country code -> font config if let Some(extra_font) = match name.city.country.as_ref() { "ir" | "ly" => Some("NotoSansArabic-Regular.ttf"), diff --git a/map_model/src/make/merge_intersections.rs b/map_model/src/make/merge_intersections.rs index 783495593e..22604db920 100644 --- a/map_model/src/make/merge_intersections.rs +++ b/map_model/src/make/merge_intersections.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeSet, VecDeque}; +use abstutil::Timer; use geom::{Angle, Distance}; use crate::osm; @@ -43,6 +44,24 @@ pub fn merge_short_roads(map: &mut RawMap, consolidate_all: bool) -> BTreeSet>( + "merge_osm_ways.json".to_string(), + &mut Timer::throwaway(), + ) { + for id in ways { + match map.merge_short_road(id) { + Ok((i, _, _, _)) => { + merged.insert(i); + } + Err(err) => { + warn!("Not merging short road / junction=intersection: {}", err); + } + } + } + } + merged }