By the power of my Mammal Hands, I will figure this out. #654

This commit is contained in:
Dustin Carlino 2021-07-19 11:21:04 -07:00
parent 68daa6884a
commit c28fef1752
7 changed files with 123 additions and 96 deletions

View File

@ -1,4 +1,4 @@
use std::collections::{hash_map::Entry, HashMap};
use std::collections::{hash_map::Entry, BTreeMap, HashMap};
use abstutil::{Counter, Timer};
use geom::{Distance, HashablePt2D, PolyLine, Pt2D};
@ -67,6 +67,7 @@ pub fn split_up_roads(
},
// Filled out later
elevation: Distance::ZERO,
trim_roads_for_merging: BTreeMap::new(),
},
);
}
@ -80,6 +81,7 @@ pub fn split_up_roads(
intersection_type: IntersectionType::StopSign,
// Filled out later
elevation: Distance::ZERO,
trim_roads_for_merging: BTreeMap::new(),
},
);
}

View File

@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::io::Write;
use abstio::{CityName, MapName};
@ -193,6 +193,7 @@ impl Model {
point,
intersection_type: IntersectionType::StopSign,
elevation: Distance::ZERO,
trim_roads_for_merging: BTreeMap::new(),
},
);
self.intersection_added(ctx, id);

View File

@ -597,7 +597,8 @@ fn recalculate_intersection_polygon(
intersection.orig_id,
intersection_roads,
&mut roads,
intersection.merged,
&BTreeMap::new(),
//intersection.merged,
)
.unwrap()
.0;

View File

@ -27,12 +27,30 @@ pub fn intersection_polygon(
intersection_id: osm::NodeID,
intersection_roads: BTreeSet<OriginalRoad>,
roads: &mut BTreeMap<OriginalRoad, Road>,
merged: bool,
trim_roads_for_merging: &BTreeMap<(osm::WayID, bool), Pt2D>,
) -> Result<(Polygon, Vec<(String, Polygon)>)> {
if intersection_roads.is_empty() {
panic!("{} has no roads", intersection_id);
}
// First pre-trim roads if it's a consolidated intersection.
for id in &intersection_roads {
if let Some(endpt) = trim_roads_for_merging.get(&(id.osm_way_id, id.i1 == intersection_id))
{
let road = roads.get_mut(id).unwrap();
if road.src_i == intersection_id {
road.trimmed_center_pts = road
.trimmed_center_pts
.get_slice_starting_at(*endpt)
.unwrap();
} else {
assert_eq!(road.dst_i, intersection_id);
road.trimmed_center_pts =
road.trimmed_center_pts.get_slice_ending_at(*endpt).unwrap();
}
}
}
// Turn all of the incident roads into two PolyLines (the "forwards" and "backwards" borders of
// the road, if the roads were oriented to both be incoming to the intersection), both ending
// at the intersection
@ -72,24 +90,26 @@ pub fn intersection_polygon(
.iter()
.map(|(r, _, _, _)| (*r, roads[r].trimmed_center_pts.clone()))
.collect::<Vec<_>>();
if let Some(result) = on_off_ramp(roads, intersection_id, lines.clone()) {
if !trim_roads_for_merging.is_empty() {
// TODO Keep this or not?
/*if let Some(fixed) = convex_hull_merged_intersection(
result.clone(),
intersection_id,
intersection_roads,
roads,
) {
return Ok((fixed, debug));
}*/
pretrimmed_geometry(roads, intersection_id, &lines)
} else if let Some(result) = on_off_ramp(roads, intersection_id, lines.clone()) {
Ok(result)
} else {
// on_off_ramp failed, so first restore lines
for (r, trimmed_center_pts) in rollback {
roads.get_mut(&r).unwrap().trimmed_center_pts = trimmed_center_pts;
}
let (result, debug) = generalized_trim_back(roads, intersection_id, &lines)?;
if merged {
if let Some(fixed) = convex_hull_merged_intersection(
result.clone(),
intersection_id,
intersection_roads,
roads,
) {
return Ok((fixed, debug));
}
}
Ok((result, debug))
generalized_trim_back(roads, intersection_id, &lines)
}
}
@ -303,6 +323,32 @@ fn generalized_trim_back(
(close_off_polygon(endpoints), debug)*/
}
fn pretrimmed_geometry(
roads: &mut BTreeMap<OriginalRoad, Road>,
i: osm::NodeID,
lines: &[(OriginalRoad, Pt2D, PolyLine, PolyLine)],
) -> Result<(Polygon, Vec<(String, Polygon)>)> {
let mut endpoints: Vec<Pt2D> = Vec::new();
for (r, _, _, _) in lines {
let r = &roads[r];
// Shift those final centers out again to find the main endpoints for the polygon.
if r.dst_i == i {
endpoints.push(r.trimmed_center_pts.shift_right(r.half_width)?.last_pt());
endpoints.push(r.trimmed_center_pts.shift_left(r.half_width)?.last_pt());
} else {
endpoints.push(r.trimmed_center_pts.shift_left(r.half_width)?.first_pt());
endpoints.push(r.trimmed_center_pts.shift_right(r.half_width)?.first_pt());
}
}
// TODO Do all of the crazy deduping that generalized_trim_back does?
let result = Ring::new(close_off_polygon(Pt2D::approx_dedupe(
endpoints,
Distance::meters(0.1),
)))?;
Ok((result.into_polygon(), Vec::new()))
}
fn deadend(
roads: &mut BTreeMap<OriginalRoad, Road>,
i: osm::NodeID,

View File

@ -61,12 +61,7 @@ pub struct Intersection {
}
impl InitialMap {
pub fn new(
raw: &RawMap,
bounds: &Bounds,
merged_intersections: &BTreeSet<osm::NodeID>,
timer: &mut Timer,
) -> InitialMap {
pub fn new(raw: &RawMap, bounds: &Bounds, timer: &mut Timer) -> InitialMap {
let mut m = InitialMap {
roads: BTreeMap::new(),
intersections: BTreeMap::new(),
@ -110,7 +105,7 @@ impl InitialMap {
i.id,
i.roads.clone(),
&mut m.roads,
merged_intersections.contains(&i.id),
&raw.intersections[&i.id].trim_roads_for_merging,
) {
Ok((poly, _)) => {
i.polygon = poly;
@ -158,7 +153,7 @@ impl InitialMap {
i.id,
i.roads.clone(),
&mut m.roads,
merged_intersections.contains(&i.id),
&raw.intersections[&i.id].trim_roads_for_merging,
)
.unwrap()
.0;

View File

@ -59,8 +59,7 @@ impl Map {
remove_disconnected::remove_disconnected_roads(&mut raw, timer);
timer.start("merging short roads");
let merged_intersections =
merge_intersections::merge_short_roads(&mut raw, opts.consolidate_all_intersections);
merge_intersections::merge_short_roads(&mut raw, opts.consolidate_all_intersections);
timer.stop("merging short roads");
timer.start("collapsing degenerate intersections");
@ -70,7 +69,7 @@ impl Map {
timer.start("raw_map to InitialMap");
let gps_bounds = raw.gps_bounds.clone();
let bounds = gps_bounds.to_bounds();
let initial_map = initial::InitialMap::new(&raw, &bounds, &merged_intersections, timer);
let initial_map = initial::InitialMap::new(&raw, &bounds, timer);
timer.stop("raw_map to InitialMap");
let mut map = Map {
@ -119,7 +118,8 @@ impl Map {
incoming_lanes: Vec::new(),
outgoing_lanes: Vec::new(),
roads: i.roads.iter().map(|id| road_id_mapping[id]).collect(),
merged: merged_intersections.contains(&i.id),
// TODO Keep trim_roads_for_merging?
merged: !raw.intersections[&i.id].trim_roads_for_merging.is_empty(),
});
intersection_id_mapping.insert(i.id, id);
}

View File

@ -184,10 +184,14 @@ impl RawMap {
);
}
// We don't yet know if there are short roads that we'll merge
let merged = false;
let (poly, debug) =
initial::intersection_polygon(id, intersection_roads, &mut roads, merged).unwrap();
// trim_roads_for_merging will be empty unless we've called merge_short_road
let (poly, debug) = initial::intersection_polygon(
id,
intersection_roads,
&mut roads,
&self.intersections[&id].trim_roads_for_merging,
)
.unwrap();
(
poly,
roads
@ -212,13 +216,12 @@ impl RawMap {
}
}
for id in [road.i1, road.i2] {
// We don't yet know if there are short roads that we'll merge
let merged = false;
initial::intersection_polygon(
id,
self.roads_per_intersection(id).into_iter().collect(),
&mut roads,
merged,
// TODO Not sure if we should use this or not
&BTreeMap::new(),
)
.unwrap();
}
@ -328,11 +331,45 @@ impl RawMap {
if i1 == i2 {
bail!("Can't merge {} -- it's a loop on {}", short, i1);
}
let i1_pt = self.intersections[&i1].point;
// Remember the original connections to i1 before we merge. None of these will change IDs.
let mut connected_to_i1 = self.roads_per_intersection(i1);
connected_to_i1.retain(|x| *x != short);
// Retain some geometry...
{
let mut trim_roads_for_merging = BTreeMap::new();
for i in vec![i1, i2] {
for r in self.roads_per_intersection(i) {
// If we keep this in there, it might accidentally overwrite the
// trim_roads_for_merging key for a surviving road!
if r == short {
continue;
}
if let Some(pl) = self.trimmed_road_geometry(r) {
if r.i1 == i {
if trim_roads_for_merging.contains_key(&(r.osm_way_id, true)) {
panic!("ahhhh dupe for {}", r);
}
trim_roads_for_merging.insert((r.osm_way_id, true), pl.first_pt());
} else {
if trim_roads_for_merging.contains_key(&(r.osm_way_id, false)) {
panic!("ahhhh dupe for {}", r);
}
trim_roads_for_merging.insert((r.osm_way_id, false), pl.last_pt());
}
} else {
panic!("no trimmed_road_geometry for {}", r);
}
}
}
self.intersections
.get_mut(&i1)
.unwrap()
.trim_roads_for_merging
.extend(trim_roads_for_merging);
}
self.roads.remove(&short).unwrap();
// Arbitrarily keep i1 and destroy i2. If the intersection types differ, upgrade the
@ -346,26 +383,6 @@ impl RawMap {
}
}
// When we delete the short road, we modify the polyline of all of the connected surviving
// roads. There are a bunch of ways we could modify them, and also decide which ones to
// even modify. These combinations are captured here.
#[allow(dead_code)]
enum ModifyGeom {
AddOnePoint,
// Destructive -- this often dramatically warps the angle of connecting roads
ChangeEndpoint,
AddAllPoints,
}
#[allow(dead_code)]
enum ModifyWhichRoads {
None,
All,
ArbitrarilyOne,
OnlyNormalRoads,
}
let modify_geom = ModifyGeom::AddOnePoint;
let modify_which = ModifyWhichRoads::All;
// Fix up all roads connected to i2. Delete them and create a new copy; the ID changes,
// since one intersection changes.
let mut deleted = vec![short];
@ -374,51 +391,13 @@ impl RawMap {
let mut new_to_old = BTreeMap::new();
for r in self.roads_per_intersection(i2) {
deleted.push(r);
let mut road = self.roads.remove(&r).unwrap();
let road = self.roads.remove(&r).unwrap();
let mut new_id = r;
if r.i1 == i2 {
new_id.i1 = i1;
if match modify_which {
ModifyWhichRoads::None => false,
ModifyWhichRoads::All => true,
ModifyWhichRoads::ArbitrarilyOne => created.is_empty(),
ModifyWhichRoads::OnlyNormalRoads => {
!road.osm_tags.is("junction", "intersection")
}
} {
match modify_geom {
ModifyGeom::AddOnePoint => {
road.center_points.insert(0, i1_pt);
}
ModifyGeom::ChangeEndpoint => {
road.center_points[0] = i1_pt;
}
ModifyGeom::AddAllPoints => todo!(),
}
}
} else {
assert_eq!(r.i2, i2);
new_id.i2 = i1;
if match modify_which {
ModifyWhichRoads::None => false,
ModifyWhichRoads::All => true,
ModifyWhichRoads::ArbitrarilyOne => created.is_empty(),
ModifyWhichRoads::OnlyNormalRoads => {
!road.osm_tags.is("junction", "intersection")
}
} {
match modify_geom {
ModifyGeom::AddOnePoint => {
road.center_points.push(i1_pt);
}
ModifyGeom::ChangeEndpoint => {
*road.center_points.last_mut().unwrap() = i1_pt;
}
ModifyGeom::AddAllPoints => todo!(),
}
}
}
old_to_new.insert(r, new_id);
new_to_old.insert(new_id, r);
@ -569,6 +548,9 @@ pub struct RawIntersection {
pub point: Pt2D,
pub intersection_type: IntersectionType,
pub elevation: Distance,
// true if src_i matches this intersection (or the deleted/consolidated one, whatever)
pub trim_roads_for_merging: BTreeMap<(osm::WayID, bool), Pt2D>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]