find all the short lanes, from map_editor

This commit is contained in:
Dustin Carlino 2019-10-26 15:01:27 -07:00
parent 4d2f77e90c
commit e881d13014
4 changed files with 84 additions and 29 deletions

View File

@ -55,6 +55,7 @@ fi
for poly in `ls data/polygons/`; do for poly in `ls data/polygons/`; do
name=`basename -s .poly $poly`; name=`basename -s .poly $poly`;
if [ ! -f data/input/$name.osm ]; then if [ ! -f data/input/$name.osm ]; then
echo "Running osmconvert for $name"
osmconvert data/input/Seattle.osm \ osmconvert data/input/Seattle.osm \
-B=data/polygons/$name.poly \ -B=data/polygons/$name.poly \
--complete-ways \ --complete-ways \

View File

@ -24,7 +24,7 @@ struct UI {
} }
enum State { enum State {
Viewing, Viewing { short_roads: HashSet<StableRoadID> },
MovingIntersection(StableIntersectionID), MovingIntersection(StableIntersectionID),
MovingBuilding(StableBuildingID), MovingBuilding(StableBuildingID),
MovingRoadPoint(StableRoadID, usize), MovingRoadPoint(StableRoadID, usize),
@ -45,6 +45,14 @@ enum State {
StampingRoads(String, String, String, String), StampingRoads(String, String, String, String),
} }
impl State {
fn viewing() -> State {
State::Viewing {
short_roads: HashSet::new(),
}
}
}
impl UI { impl UI {
fn new(ctx: &EventCtx) -> UI { fn new(ctx: &EventCtx) -> UI {
let mut args = CmdArgs::new(); let mut args = CmdArgs::new();
@ -69,7 +77,7 @@ impl UI {
}; };
let mut ui = UI { let mut ui = UI {
model, model,
state: State::Viewing, state: State::viewing(),
menu: ModalMenu::new( menu: ModalMenu::new(
"Map Editor", "Map Editor",
vec![vec![ vec![vec![
@ -80,6 +88,8 @@ impl UI {
(None, "produce OSM parking+sidewalk diff"), (None, "produce OSM parking+sidewalk diff"),
(hotkey(Key::G), "preview all intersections"), (hotkey(Key::G), "preview all intersections"),
(None, "find overlapping intersections"), (None, "find overlapping intersections"),
(None, "find short roads"),
(None, "clear short roads"),
]], ]],
ctx, ctx,
), ),
@ -124,7 +134,9 @@ impl GUI for UI {
} }
match self.state { match self.state {
State::Viewing => { State::Viewing {
ref mut short_roads,
} => {
{ {
let before = match self.last_id { let before = match self.last_id {
Some(ID::Road(r)) | Some(ID::RoadPoint(r, _)) => Some(r), Some(ID::Road(r)) | Some(ID::RoadPoint(r, _)) => Some(r),
@ -289,6 +301,10 @@ impl GUI for UI {
} else if self.menu.action("find overlapping intersections") { } else if self.menu.action("find overlapping intersections") {
let (draw, labels) = find_overlapping_intersections(&self.model, ctx); let (draw, labels) = find_overlapping_intersections(&self.model, ctx);
self.state = State::PreviewIntersection(draw, labels, false); self.state = State::PreviewIntersection(draw, labels, false);
} else if self.menu.action("find short roads") {
*short_roads = find_short_roads(&self.model);
} else if self.menu.action("clear short roads") {
short_roads.clear();
} }
} }
} }
@ -297,7 +313,7 @@ impl GUI for UI {
if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() { if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() {
self.model.move_i(id, cursor, ctx.prerender); self.model.move_i(id, cursor, ctx.prerender);
if ctx.input.key_released(Key::LeftControl) { if ctx.input.key_released(Key::LeftControl) {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
} }
@ -305,7 +321,7 @@ impl GUI for UI {
if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() { if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() {
self.model.move_b(id, cursor, ctx.prerender); self.model.move_b(id, cursor, ctx.prerender);
if ctx.input.key_released(Key::LeftControl) { if ctx.input.key_released(Key::LeftControl) {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
} }
@ -313,7 +329,7 @@ impl GUI for UI {
if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() { if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() {
self.model.move_r_pt(r, idx, cursor, ctx.prerender); self.model.move_r_pt(r, idx, cursor, ctx.prerender);
if ctx.input.key_released(Key::LeftControl) { if ctx.input.key_released(Key::LeftControl) {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
} }
@ -327,9 +343,9 @@ impl GUI for UI {
.unwrap_or_else(String::new), .unwrap_or_else(String::new),
) { ) {
self.model.set_b_label(id, label, ctx.prerender); self.model.set_b_label(id, label, ctx.prerender);
self.state = State::Viewing; self.state = State::viewing();
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
State::LabelingRoad(r, ref mut wizard) => { State::LabelingRoad(r, ref mut wizard) => {
@ -342,9 +358,9 @@ impl GUI for UI {
.unwrap_or_else(String::new), .unwrap_or_else(String::new),
) { ) {
self.model.set_r_label(r, label, ctx.prerender); self.model.set_r_label(r, label, ctx.prerender);
self.state = State::Viewing; self.state = State::viewing();
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
State::LabelingIntersection(id, ref mut wizard) => { State::LabelingIntersection(id, ref mut wizard) => {
@ -356,19 +372,19 @@ impl GUI for UI {
.unwrap_or_else(String::new), .unwrap_or_else(String::new),
) { ) {
self.model.set_i_label(id, label, ctx.prerender); self.model.set_i_label(id, label, ctx.prerender);
self.state = State::Viewing; self.state = State::viewing();
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
State::CreatingRoad(i1) => { State::CreatingRoad(i1) => {
if ctx.input.key_pressed(Key::Escape, "stop defining road") { if ctx.input.key_pressed(Key::Escape, "stop defining road") {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} else if let Some(ID::Intersection(i2)) = self.model.world.get_selection() { } else if let Some(ID::Intersection(i2)) = self.model.world.get_selection() {
if i1 != i2 && ctx.input.key_pressed(Key::R, "finalize road") { if i1 != i2 && ctx.input.key_pressed(Key::R, "finalize road") {
self.model.create_r(i1, i2, ctx.prerender); self.model.create_r(i1, i2, ctx.prerender);
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
} }
@ -379,10 +395,10 @@ impl GUI for UI {
self.model.map.roads[&id].get_spec().to_string(), self.model.map.roads[&id].get_spec().to_string(),
) { ) {
self.model.edit_lanes(id, s, ctx.prerender); self.model.edit_lanes(id, s, ctx.prerender);
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
} }
@ -416,7 +432,7 @@ impl GUI for UI {
} }
} }
if done || wizard.aborted() { if done || wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
} }
@ -424,9 +440,9 @@ impl GUI for UI {
if let Some(name) = wizard.wrap(ctx).input_string("Name the synthetic map") { if let Some(name) = wizard.wrap(ctx).input_string("Name the synthetic map") {
self.model.map.name = name; self.model.map.name = name;
self.model.export(); self.model.export();
self.state = State::Viewing; self.state = State::viewing();
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
} }
} }
State::SelectingRectangle(pt1, ref mut pt2, ref mut keydown) => { State::SelectingRectangle(pt1, ref mut pt2, ref mut keydown) => {
@ -442,7 +458,7 @@ impl GUI for UI {
} }
} }
if ctx.input.key_pressed(Key::Escape, "stop selecting area") { if ctx.input.key_pressed(Key::Escape, "stop selecting area") {
self.state = State::Viewing; self.state = State::viewing();
} else if ctx } else if ctx
.input .input
.key_pressed(Key::Backspace, "delete everything in area") .key_pressed(Key::Backspace, "delete everything in area")
@ -451,7 +467,7 @@ impl GUI for UI {
self.model.delete_everything_inside(rect, ctx.prerender); self.model.delete_everything_inside(rect, ctx.prerender);
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
self.state = State::Viewing; self.state = State::viewing();
} }
} }
State::CreatingTurnRestrictionPt1(from) => { State::CreatingTurnRestrictionPt1(from) => {
@ -459,7 +475,7 @@ impl GUI for UI {
.input .input
.key_pressed(Key::Escape, "stop defining turn restriction") .key_pressed(Key::Escape, "stop defining turn restriction")
{ {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} else if let Some(ID::Road(to)) = self.model.world.get_selection() { } else if let Some(ID::Road(to)) = self.model.world.get_selection() {
if ctx if ctx
@ -487,10 +503,10 @@ impl GUI for UI {
}) })
{ {
self.model.add_tr(from, restriction, to, ctx.prerender); self.model.add_tr(from, restriction, to, ctx.prerender);
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
} }
@ -505,7 +521,7 @@ impl GUI for UI {
.input .input
.key_pressed(Key::P, "stop previewing intersection") .key_pressed(Key::P, "stop previewing intersection")
{ {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
} }
@ -527,10 +543,10 @@ impl GUI for UI {
if !ok { if !ok {
println!("Sorry, don't understand {}", line); println!("Sorry, don't understand {}", line);
} }
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} else if wizard.aborted() { } else if wizard.aborted() {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} }
} }
@ -539,7 +555,7 @@ impl GUI for UI {
.input .input
.key_pressed(Key::Escape, "stop copying road metadata") .key_pressed(Key::Escape, "stop copying road metadata")
{ {
self.state = State::Viewing; self.state = State::viewing();
self.model.world.handle_mouseover(ctx); self.model.world.handle_mouseover(ctx);
} else if let Some(ID::Road(id)) = self.model.world.get_selection() { } else if let Some(ID::Road(id)) = self.model.world.get_selection() {
if ctx.input.key_pressed( if ctx.input.key_pressed(
@ -614,7 +630,13 @@ impl GUI for UI {
| State::EnteringWarp(ref wizard) => { | State::EnteringWarp(ref wizard) => {
wizard.draw(g); wizard.draw(g);
} }
State::Viewing => {} State::Viewing { ref short_roads } => {
for r in short_roads {
if let Some(p) = self.model.world.get_unioned_polygon(ID::Road(*r)) {
g.draw_polygon(Color::CYAN, p);
}
}
}
State::MovingIntersection(_) State::MovingIntersection(_)
| State::MovingBuilding(_) | State::MovingBuilding(_)
| State::MovingRoadPoint(_, _) | State::MovingRoadPoint(_, _)
@ -736,6 +758,26 @@ fn find_overlapping_intersections(model: &Model, ctx: &EventCtx) -> (Drawable, V
(ctx.prerender.upload(batch), Vec::new()) (ctx.prerender.upload(batch), Vec::new())
} }
// TODO StableRoadID is dangerous, as this map changes. :\
fn find_short_roads(model: &Model) -> HashSet<StableRoadID> {
// Assume the full map has been built. We really care about short lanes there.
let map: map_model::Map = abstutil::read_binary(
&abstutil::path_map(&model.map.name),
&mut Timer::throwaway(),
)
.unwrap();
// Buses are 12.5
let threshold = Distance::meters(13.0);
let mut roads: HashSet<StableRoadID> = HashSet::new();
for l in map.all_lanes() {
if l.length() < threshold {
roads.insert(map.get_r(l.parent).stable_id);
}
}
println!("{} short roads", roads.len());
roads
}
fn main() { fn main() {
ezgui::run( ezgui::run(
ezgui::Settings::new("Synthetic map editor", (1800.0, 800.0)), ezgui::Settings::new("Synthetic map editor", (1800.0, 800.0)),

View File

@ -153,4 +153,8 @@ impl<ID: ObjectID> World<ID> {
let obj = self.objects.remove(&id).unwrap(); let obj = self.objects.remove(&id).unwrap();
self.quadtree.remove(obj.quadtree_id).unwrap(); self.quadtree.remove(obj.quadtree_id).unwrap();
} }
pub fn get_unioned_polygon(&self, id: ID) -> Option<&Polygon> {
Some(&self.objects.get(&id)?.unioned_polygon)
}
} }

View File

@ -419,13 +419,21 @@ impl RawMap {
let road = self.roads.get_mut(&r).unwrap(); let road = self.roads.get_mut(&r).unwrap();
if road.i1 == i2 { if road.i1 == i2 {
road.i1 = i1; road.i1 = i1;
road.center_points[0] = i1_pt; road.center_points[0] = i1_pt;
// TODO More extreme: All of the points of the short road. Except there usually
// aren't many, since they're short.
//road.center_points.insert(0, i1_pt);
// TODO Should we even do this? // TODO Should we even do this?
road.orig_id.node1 = i1_orig_id.osm_node_id; road.orig_id.node1 = i1_orig_id.osm_node_id;
} else { } else {
assert_eq!(road.i2, i2); assert_eq!(road.i2, i2);
road.i2 = i1; road.i2 = i1;
*road.center_points.last_mut().unwrap() = i1_pt; *road.center_points.last_mut().unwrap() = i1_pt;
//road.center_points.push(i1_pt);
// TODO Should we even do this? // TODO Should we even do this?
road.orig_id.node2 = i1_orig_id.osm_node_id; road.orig_id.node2 = i1_orig_id.osm_node_id;
} }