slightly better border matching for buses. dont count on any ordering in

the route relation. include intersections that get copied as
possibilities.
This commit is contained in:
Dustin Carlino 2020-07-15 17:27:09 -07:00
parent acc82b4f06
commit b942510f67
6 changed files with 74 additions and 51 deletions

View File

@ -1,7 +1,8 @@
use abstutil::{retain_btreemap, Timer}; use abstutil::{retain_btreemap, Timer};
use geom::{PolyLine, Ring}; use geom::{PolyLine, Pt2D, Ring};
use map_model::raw::{OriginalIntersection, OriginalRoad, RawMap}; use map_model::raw::{OriginalIntersection, OriginalRoad, RawMap};
use map_model::IntersectionType; use map_model::IntersectionType;
use std::collections::BTreeMap;
// TODO This needs to update turn restrictions too // TODO This needs to update turn restrictions too
pub fn clip_map(map: &mut RawMap, timer: &mut Timer) { pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
@ -27,6 +28,11 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
first_in || last_in || light_rail_ok first_in || last_in || light_rail_ok
}); });
// When we split an intersection out of bounds into two, one of them gets a new ID. Remember
// that here.
let mut extra_borders: BTreeMap<OriginalIntersection, (OriginalIntersection, Pt2D)> =
BTreeMap::new();
// First pass: Clip roads beginning out of bounds // First pass: Clip roads beginning out of bounds
let road_ids: Vec<OriginalRoad> = map.roads.keys().cloned().collect(); let road_ids: Vec<OriginalRoad> = map.roads.keys().cloned().collect();
for id in road_ids { for id in road_ids {
@ -36,6 +42,7 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
} }
let mut move_i = id.i1; let mut move_i = id.i1;
let orig_id = id.i1;
// The road crosses the boundary. If the intersection happens to have another connected // The road crosses the boundary. If the intersection happens to have another connected
// road, then we need to copy the intersection before trimming it. This effectively // road, then we need to copy the intersection before trimming it. This effectively
@ -53,6 +60,7 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
move_i = OriginalIntersection { move_i = OriginalIntersection {
osm_node_id: map.new_osm_node_id(-1), osm_node_id: map.new_osm_node_id(-1),
}; };
extra_borders.insert(orig_id, (move_i, copy.point));
map.intersections.insert(move_i, copy); map.intersections.insert(move_i, copy);
println!("Disconnecting {} from some other stuff (starting OOB)", id); println!("Disconnecting {} from some other stuff (starting OOB)", id);
} }
@ -94,6 +102,7 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
} }
let mut move_i = id.i2; let mut move_i = id.i2;
let orig_id = id.i2;
// The road crosses the boundary. If the intersection happens to have another connected // The road crosses the boundary. If the intersection happens to have another connected
// road, then we need to copy the intersection before trimming it. This effectively // road, then we need to copy the intersection before trimming it. This effectively
@ -110,6 +119,7 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
move_i = OriginalIntersection { move_i = OriginalIntersection {
osm_node_id: map.new_osm_node_id(-1), osm_node_id: map.new_osm_node_id(-1),
}; };
extra_borders.insert(orig_id, (move_i, copy.point));
map.intersections.insert(move_i, copy); map.intersections.insert(move_i, copy);
println!("Disconnecting {} from some other stuff (ending OOB)", id); println!("Disconnecting {} from some other stuff (ending OOB)", id);
} }
@ -163,41 +173,48 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
let mut keep_routes = Vec::new(); let mut keep_routes = Vec::new();
for mut r in map.bus_routes.drain(..) { for mut r in map.bus_routes.drain(..) {
let mut borders = Vec::new(); let mut borders: Vec<(OriginalIntersection, Pt2D)> = Vec::new();
let num_pts = r.all_pts.len(); for pt in r.all_pts.drain(..) {
for (idx, pt) in r.all_pts.drain(..).enumerate() { if let Some(i) = map.intersections.get(&pt) {
if map if i.intersection_type == IntersectionType::Border {
.intersections borders.push((pt, i.point));
.get(&pt)
.map(|i| i.intersection_type == IntersectionType::Border)
.unwrap_or(false)
{
borders.push((pt, idx));
}
}
if borders.len() > 2 {
timer.warn(format!(
"Route {} matches too many borders: {:?}",
r.osm_rel_id, borders
));
} else {
// https://wiki.openstreetmap.org/w/index.php?title=Relation:route&uselang=en#Order_matters
// Of course the ways aren't in order. :( Use distance to the first/last stop. If
// there's just one stop, we're just gambling at this point.
if borders.len() == 2 {
// Presumably the borders are in order.
r.border_start = Some(borders[0].0);
r.border_end = Some(borders[1].0);
} else if borders.len() == 1 {
// Alright, which end is which? Use the original index of the point to guess.
if borders[0].1 < num_pts / 2 {
r.border_start = Some(borders[0].0);
} else {
r.border_end = Some(borders[0].0);
} }
} }
keep_routes.push(r); if let Some(pair) = extra_borders.get(&pt) {
borders.push(*pair);
}
} }
if !borders.is_empty() {
// Guess which border is for the beginning and end of the route. This can fail if:
// - there's just one stop
// - the border isn't actually connected to the stop by any path (roads causing copied
// intersections trigger this)
let start_pt = r.stops[0].vehicle_pos;
let closest_to_start = borders
.iter()
.min_by_key(|(_, pt)| start_pt.dist_to(*pt))
.unwrap();
let end_pt = r.stops.last().unwrap().vehicle_pos;
let closest_to_end = borders
.iter()
.min_by_key(|(_, pt)| end_pt.dist_to(*pt))
.unwrap();
if closest_to_start.0 != closest_to_end.0 {
r.border_start = Some(closest_to_start.0);
r.border_end = Some(closest_to_end.0);
} else {
// Break the tie...
if closest_to_start.1.dist_to(start_pt) < closest_to_end.1.dist_to(end_pt) {
r.border_start = Some(closest_to_start.0);
} else {
r.border_end = Some(closest_to_end.0);
}
}
}
// TODO Warn for some of these weird things and maybe skip
keep_routes.push(r);
} }
map.bus_routes = keep_routes; map.bus_routes = keep_routes;

View File

@ -126,7 +126,10 @@ fn choose_polygon(wiz: &mut Wizard, ctx: &mut EventCtx, _: &mut App) -> Option<T
let name = wiz.wrap(ctx).choose_string("Edit which polygon?", || { let name = wiz.wrap(ctx).choose_string("Edit which polygon?", || {
abstutil::list_all_objects(abstutil::path("input/seattle/polygons/")) abstutil::list_all_objects(abstutil::path("input/seattle/polygons/"))
})?; })?;
match LonLat::read_osmosis_polygon(format!("input/seattle/polygons/{}.poly", name)) { match LonLat::read_osmosis_polygon(abstutil::path(format!(
"input/seattle/polygons/{}.poly",
name
))) {
Ok(pts) => Some(Transition::Replace(polygon::PolygonEditor::new( Ok(pts) => Some(Transition::Replace(polygon::PolygonEditor::new(
ctx, name, pts, ctx, name, pts,
))), ))),

View File

@ -146,7 +146,7 @@ impl State for PolygonEditor {
// https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format // https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format
fn save_as_osmosis(name: &str, pts: &Vec<LonLat>) -> Result<(), Error> { fn save_as_osmosis(name: &str, pts: &Vec<LonLat>) -> Result<(), Error> {
let path = "bounding_boy.poly"; let path = format!("{}.poly", name);
let mut f = File::create(&path)?; let mut f = File::create(&path)?;
writeln!(f, "{}", name)?; writeln!(f, "{}", name)?;

View File

@ -227,14 +227,20 @@ impl ShowBusRoute {
bus_locations.push(pt); bus_locations.push(pt);
} }
let mut colorer = ColorDiscrete::new( let mut categories = vec![("route", app.cs.unzoomed_bus)];
app, if route.start_border.is_some() {
vec![ categories.push(("start", Color::RED));
("route", app.cs.unzoomed_bus), }
("start", Color::RED), if route.end_border.is_some() {
("end", Color::GREEN), categories.push(("end", Color::GREEN));
], }
); let mut colorer = ColorDiscrete::new(app, categories);
if let Some(l) = route.start_border {
colorer.add_i(map.get_l(l).src_i, "start");
}
if let Some(l) = route.end_border {
colorer.add_i(map.get_l(l).dst_i, "end");
}
for pair in route.stops.windows(2) { for pair in route.stops.windows(2) {
for step in map for step in map
.pathfind(PathRequest { .pathfind(PathRequest {
@ -250,12 +256,6 @@ impl ShowBusRoute {
} }
} }
} }
if let Some(l) = route.start_border {
colorer.add_i(map.get_l(l).src_i, "start");
}
if let Some(l) = route.end_border {
colorer.add_i(map.get_l(l).dst_i, "end");
}
let mut labels = Vec::new(); let mut labels = Vec::new();
for (idx, bs) in route.stops.iter().enumerate() { for (idx, bs) in route.stops.iter().enumerate() {

View File

@ -99,8 +99,9 @@ fn make_route(
} else { } else {
// TODO Should panic // TODO Should panic
println!( println!(
"Route {} starts at {}, but no starting lane for a {:?}?", "Route {} starts at {} ({}), but no starting lane for a {:?}?",
rel_url(r.osm_rel_id), rel_url(r.osm_rel_id),
i.id,
i.orig_id, i.orig_id,
route_type route_type
); );
@ -116,8 +117,9 @@ fn make_route(
} else { } else {
// TODO Should panic // TODO Should panic
println!( println!(
"Route {} ends at {}, but no ending lane for a {:?}?", "Route {} ends at {} ({}), but no ending lane for a {:?}?",
rel_url(r.osm_rel_id), rel_url(r.osm_rel_id),
i.id,
i.orig_id, i.orig_id,
route_type route_type
); );

View File

@ -155,6 +155,7 @@ impl RawMap {
} }
} }
// TODO Almost gone...
pub fn new_osm_way_id(&self, start: i64) -> i64 { pub fn new_osm_way_id(&self, start: i64) -> i64 {
assert!(start < 0); assert!(start < 0);
// Slow, but deterministic. // Slow, but deterministic.