mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
generalize the R253 fix
This commit is contained in:
parent
18391811e4
commit
949b184678
@ -8,16 +8,10 @@
|
||||
- bad polyline shifting causes jagged lane endings in generalized_trim_back
|
||||
|
||||
- handle small roads again somehow?
|
||||
- what's going on with R253 generally?
|
||||
- automate the manual fix. check it in larger 23rd map.
|
||||
|
||||
- I40 has a long cut when merged, why not hit in the middle?
|
||||
- what if we allow intersections between infinite lines for merged cases?
|
||||
- try it bigger
|
||||
- deal with loop roads?
|
||||
|
||||
- manually draw a picture of the weird intersection to see what would look reasonable. i think we need original road bands from deleted stuff to make decent polygons.
|
||||
|
||||
- model U-turns
|
||||
|
||||
- degenerate-2's should only have one crosswalk
|
||||
|
125
map_model/src/make/initial/fix_ramps.rs
Normal file
125
map_model/src/make/initial/fix_ramps.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use crate::make::initial::{geometry, InitialMap};
|
||||
use crate::raw_data::{StableIntersectionID, StableRoadID};
|
||||
use abstutil::Timer;
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
|
||||
pub fn fix_ramps(m: &mut InitialMap, timer: &mut Timer) {
|
||||
// Look for road center lines that hit an intersection polygon that isn't one of their
|
||||
// endpoints.
|
||||
timer.start_iter(
|
||||
"look for roads crossing intersections in strange ways",
|
||||
m.roads.len(),
|
||||
);
|
||||
let mut fixme: Vec<(StableRoadID, StableIntersectionID)> = Vec::new();
|
||||
for r in m.roads.values() {
|
||||
timer.next();
|
||||
// TODO Prune search.
|
||||
for i in m.intersections.values() {
|
||||
if r.src_i == i.id || r.dst_i == i.id {
|
||||
continue;
|
||||
}
|
||||
if !r.trimmed_center_pts.crosses_polygon(&i.polygon) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO Avoid some false positives by seeing if this road is "close" to the
|
||||
// intersection it crosses. This probably needs more tuning. It avoids expected
|
||||
// tunnel/bridge crossings.
|
||||
if !floodfill(m, i.id, 5).contains(&r.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO Still seeing false positives due to lack of short road merging.
|
||||
|
||||
fixme.push((r.id, i.id));
|
||||
}
|
||||
}
|
||||
|
||||
for (r, i) in fixme {
|
||||
if fix_ramp(m, r, i) {
|
||||
info!("Fixed ramp {} crossing {}", r, i);
|
||||
} else {
|
||||
info!("{} crosses {} strangely, but didn't change anything", r, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn floodfill(m: &InitialMap, start: StableIntersectionID, steps: usize) -> HashSet<StableRoadID> {
|
||||
let mut seen: HashSet<StableRoadID> = HashSet::new();
|
||||
let mut queue: Vec<(StableRoadID, usize)> = m.intersections[&start]
|
||||
.roads
|
||||
.iter()
|
||||
.map(|r| (*r, 1))
|
||||
.collect();
|
||||
while !queue.is_empty() {
|
||||
let (r, count) = queue.pop().unwrap();
|
||||
if seen.contains(&r) {
|
||||
continue;
|
||||
}
|
||||
seen.insert(r);
|
||||
if count < steps {
|
||||
for next in m.intersections[&m.roads[&r].src_i]
|
||||
.roads
|
||||
.iter()
|
||||
.chain(m.intersections[&m.roads[&r].dst_i].roads.iter())
|
||||
{
|
||||
queue.push((*next, count + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
seen
|
||||
}
|
||||
|
||||
fn fix_ramp(m: &mut InitialMap, ramp: StableRoadID, new_src: StableIntersectionID) -> bool {
|
||||
// Trace backwards...
|
||||
let mut delete_roads: Vec<StableRoadID> = Vec::new();
|
||||
let mut delete_intersections: Vec<StableIntersectionID> = Vec::new();
|
||||
|
||||
let last_normal_intersection = {
|
||||
let mut current_road = ramp;
|
||||
loop {
|
||||
let src_i = &m.intersections[&m.roads[¤t_road].src_i];
|
||||
if let Some(other_road) = get_one_other(&src_i.roads, current_road) {
|
||||
delete_intersections.push(src_i.id);
|
||||
current_road = other_road;
|
||||
delete_roads.push(current_road);
|
||||
} else {
|
||||
break src_i.id;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(last_road) = delete_roads.last() {
|
||||
let mut i = m.intersections.get_mut(&last_normal_intersection).unwrap();
|
||||
i.roads.remove(&last_road);
|
||||
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
|
||||
} else {
|
||||
// TODO Not really sure why, but when there's not a road in between, don't apply the fix.
|
||||
return false;
|
||||
}
|
||||
for r in delete_roads {
|
||||
m.roads.remove(&r);
|
||||
}
|
||||
for i in delete_intersections {
|
||||
m.intersections.remove(&i);
|
||||
}
|
||||
|
||||
{
|
||||
m.roads.get_mut(&ramp).unwrap().src_i = new_src;
|
||||
let mut i = m.intersections.get_mut(&new_src).unwrap();
|
||||
i.roads.insert(ramp);
|
||||
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn get_one_other<X: PartialEq + Clone>(set: &BTreeSet<X>, item: X) -> Option<X> {
|
||||
if set.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
let items: Vec<X> = set.iter().cloned().collect();
|
||||
if items[0] == item {
|
||||
return Some(items[1].clone());
|
||||
}
|
||||
return Some(items[0].clone());
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
mod fix_ramps;
|
||||
mod geometry;
|
||||
pub mod lane_specs;
|
||||
mod merge;
|
||||
|
||||
use crate::raw_data::{StableIntersectionID, StableRoadID};
|
||||
use crate::{raw_data, MapEdits, LANE_THICKNESS};
|
||||
use abstutil::{note, Timer};
|
||||
use abstutil::Timer;
|
||||
use geom::{Bounds, Distance, GPSBounds, PolyLine, Pt2D};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct InitialMap {
|
||||
@ -139,64 +140,7 @@ impl InitialMap {
|
||||
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
|
||||
}
|
||||
|
||||
// TODO Move to a module if this grows.
|
||||
// Look for road center lines that hit an intersection polygon that isn't one of their
|
||||
// endpoints.
|
||||
timer.start_iter(
|
||||
"look for roads crossing intersections in strange ways",
|
||||
m.roads.len(),
|
||||
);
|
||||
for r in m.roads.values() {
|
||||
timer.next();
|
||||
// TODO Prune search.
|
||||
for i in m.intersections.values() {
|
||||
if r.src_i == i.id || r.dst_i == i.id {
|
||||
continue;
|
||||
}
|
||||
if !r.trimmed_center_pts.crosses_polygon(&i.polygon) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO Avoid some false positives by seeing if this road is "close" to the
|
||||
// intersection it crosses. This probably needs more tuning. It avoids expected
|
||||
// tunnel/bridge crossings.
|
||||
if !m.floodfill(i.id, 5).contains(&r.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO Still seeing false positives due to lack of short road merging.
|
||||
|
||||
note(format!("{} is suspicious -- it hits {}", r.id, i.id));
|
||||
}
|
||||
}
|
||||
|
||||
if false {
|
||||
// Delete I247 and R370. remove connection of R370 from I309.
|
||||
m.intersections.remove(&StableIntersectionID(247));
|
||||
m.roads.remove(&StableRoadID(370));
|
||||
m.intersections
|
||||
.get_mut(&StableIntersectionID(309))
|
||||
.unwrap()
|
||||
.roads
|
||||
.remove(&StableRoadID(370));
|
||||
// make R253's src be the intersection it hits. recalculate that intersection.
|
||||
m.roads.get_mut(&StableRoadID(253)).unwrap().src_i = StableIntersectionID(119);
|
||||
m.intersections
|
||||
.get_mut(&StableIntersectionID(119))
|
||||
.unwrap()
|
||||
.roads
|
||||
.insert(StableRoadID(253));
|
||||
// TODO reset geometry or not?
|
||||
{
|
||||
let i = m.intersections.get_mut(&StableIntersectionID(119)).unwrap();
|
||||
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
|
||||
}
|
||||
{
|
||||
// Also fix up this one.
|
||||
let i = m.intersections.get_mut(&StableIntersectionID(309)).unwrap();
|
||||
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
|
||||
}
|
||||
}
|
||||
fix_ramps::fix_ramps(&mut m, timer);
|
||||
|
||||
merge::short_roads(&mut m);
|
||||
|
||||
@ -213,30 +157,4 @@ impl InitialMap {
|
||||
abstutil::write_binary(&path, self).expect(&format!("Saving {} failed", path));
|
||||
info!("Saved {}", path);
|
||||
}
|
||||
|
||||
fn floodfill(&self, start: StableIntersectionID, steps: usize) -> HashSet<StableRoadID> {
|
||||
let mut seen: HashSet<StableRoadID> = HashSet::new();
|
||||
let mut queue: Vec<(StableRoadID, usize)> = self.intersections[&start]
|
||||
.roads
|
||||
.iter()
|
||||
.map(|r| (*r, 1))
|
||||
.collect();
|
||||
while !queue.is_empty() {
|
||||
let (r, count) = queue.pop().unwrap();
|
||||
if seen.contains(&r) {
|
||||
continue;
|
||||
}
|
||||
seen.insert(r);
|
||||
if count < steps {
|
||||
for next in self.intersections[&self.roads[&r].src_i]
|
||||
.roads
|
||||
.iter()
|
||||
.chain(self.intersections[&self.roads[&r].dst_i].roads.iter())
|
||||
{
|
||||
queue.push((*next, count + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
seen
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user