mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
By the power of my Mammal Hands, I will figure this out. #654
This commit is contained in:
parent
68daa6884a
commit
c28fef1752
@ -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(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -597,7 +597,8 @@ fn recalculate_intersection_polygon(
|
||||
intersection.orig_id,
|
||||
intersection_roads,
|
||||
&mut roads,
|
||||
intersection.merged,
|
||||
&BTreeMap::new(),
|
||||
//intersection.merged,
|
||||
)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user