mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 15:33:44 +03:00
Don't create RawRoads too early (before splitting ways into actual segments). Otherwise, we can't enforce invariants on RawRoads properly.
This commit is contained in:
parent
43c946a2b6
commit
6974d26cac
@ -8,15 +8,15 @@ use geom::{Distance, FindClosest, HashablePt2D, Polygon, Pt2D, Ring};
|
||||
use kml::{ExtraShape, ExtraShapes};
|
||||
use raw_map::{
|
||||
osm, Amenity, AreaType, Direction, DrivingSide, NamePerLanguage, RawArea, RawBuilding, RawMap,
|
||||
RawParkingLot, RawRoad, RestrictionType,
|
||||
RawParkingLot, RestrictionType,
|
||||
};
|
||||
|
||||
use crate::osm_geom::{get_multipolygon_members, glue_multipolygon, multipoly_geometry};
|
||||
use crate::Options;
|
||||
|
||||
pub struct OsmExtract {
|
||||
/// Unsplit roads
|
||||
pub roads: Vec<(WayID, RawRoad)>,
|
||||
/// Unsplit roads. These aren't RawRoads yet, because they may not obey those invariants.
|
||||
pub roads: Vec<(WayID, Vec<Pt2D>, Tags)>,
|
||||
/// Traffic signals to the direction they apply
|
||||
pub traffic_signals: HashMap<HashablePt2D, Direction>,
|
||||
pub osm_node_ids: HashMap<HashablePt2D, NodeID>,
|
||||
@ -109,10 +109,7 @@ pub fn extract_osm(
|
||||
way.tags.insert(osm::SIDEWALK, "right");
|
||||
}
|
||||
|
||||
out.roads.push((
|
||||
id,
|
||||
RawRoad::new(way.pts.clone(), way.tags.clone(), &opts.map_config),
|
||||
));
|
||||
out.roads.push((id, way.pts.clone(), way.tags.clone()));
|
||||
continue;
|
||||
} else if way.tags.is(osm::HIGHWAY, "service") {
|
||||
// If we got here, is_road didn't interpret it as a normal road
|
||||
@ -568,33 +565,30 @@ fn get_area_type(tags: &Tags) -> Option<AreaType> {
|
||||
|
||||
// Look for any service roads that collide with parking lots, and treat them as parking aisles
|
||||
// instead.
|
||||
fn find_parking_aisles(map: &mut RawMap, roads: &mut Vec<(WayID, RawRoad)>) {
|
||||
fn find_parking_aisles(map: &mut RawMap, roads: &mut Vec<(WayID, Vec<Pt2D>, Tags)>) {
|
||||
let mut closest: FindClosest<usize> = FindClosest::new(&map.gps_bounds.to_bounds());
|
||||
for (idx, lot) in map.parking_lots.iter().enumerate() {
|
||||
closest.add(idx, lot.polygon.points());
|
||||
}
|
||||
let mut keep_roads = Vec::new();
|
||||
let mut parking_aisles = Vec::new();
|
||||
for (id, road) in roads.drain(..) {
|
||||
if !road.osm_tags.is(osm::HIGHWAY, "service") {
|
||||
keep_roads.push((id, road));
|
||||
for (id, pts, osm_tags) in roads.drain(..) {
|
||||
if !osm_tags.is(osm::HIGHWAY, "service") {
|
||||
keep_roads.push((id, pts, osm_tags));
|
||||
continue;
|
||||
}
|
||||
// TODO This code is repeated later in make/parking_lots.rs, but oh well.
|
||||
|
||||
// Use the center of all the aisle points to match it to lots
|
||||
let candidates: Vec<usize> = closest
|
||||
.all_close_pts(
|
||||
Pt2D::center(&road.osm_center_points),
|
||||
Distance::meters(500.0),
|
||||
)
|
||||
.all_close_pts(Pt2D::center(&pts), Distance::meters(500.0))
|
||||
.into_iter()
|
||||
.map(|(idx, _, _)| idx)
|
||||
.collect();
|
||||
if service_road_crosses_parking_lot(map, &road, candidates) {
|
||||
parking_aisles.push((id, road.osm_center_points.clone()));
|
||||
if service_road_crosses_parking_lot(map, &pts, candidates) {
|
||||
parking_aisles.push((id, pts));
|
||||
} else {
|
||||
keep_roads.push((id, road));
|
||||
keep_roads.push((id, pts, osm_tags));
|
||||
}
|
||||
}
|
||||
roads.extend(keep_roads);
|
||||
@ -603,8 +597,8 @@ fn find_parking_aisles(map: &mut RawMap, roads: &mut Vec<(WayID, RawRoad)>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn service_road_crosses_parking_lot(map: &RawMap, road: &RawRoad, candidates: Vec<usize>) -> bool {
|
||||
if let Ok((polylines, rings)) = Ring::split_points(&road.osm_center_points) {
|
||||
fn service_road_crosses_parking_lot(map: &RawMap, pts: &[Pt2D], candidates: Vec<usize>) -> bool {
|
||||
if let Ok((polylines, rings)) = Ring::split_points(pts) {
|
||||
for pl in polylines {
|
||||
for idx in &candidates {
|
||||
if map.parking_lots[*idx].polygon.clip_polyline(&pl).is_some() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::{hash_map::Entry, HashMap, HashSet};
|
||||
|
||||
use abstutil::{Counter, Timer};
|
||||
use geom::{Distance, HashablePt2D, Pt2D};
|
||||
use abstutil::{Counter, Tags, Timer};
|
||||
use geom::{Distance, HashablePt2D, PolyLine, Pt2D};
|
||||
use raw_map::{
|
||||
osm, Amenity, Direction, IntersectionType, OriginalRoad, RawIntersection, RawMap, RawRoad,
|
||||
};
|
||||
@ -22,34 +22,30 @@ pub fn split_up_roads(map: &mut RawMap, mut input: OsmExtract, timer: &mut Timer
|
||||
let mut roundabout_centers: HashMap<osm::NodeID, Pt2D> = HashMap::new();
|
||||
let mut pt_to_intersection: HashMap<HashablePt2D, osm::NodeID> = HashMap::new();
|
||||
|
||||
{
|
||||
let mut roads = std::mem::take(&mut input.roads);
|
||||
roads.retain(|(id, r)| {
|
||||
if should_collapse_roundabout(r) {
|
||||
info!("Collapsing tiny roundabout {}", id);
|
||||
// Arbitrarily use the first node's ID
|
||||
let id = input.osm_node_ids[&r.osm_center_points[0].to_hashable()];
|
||||
roundabout_centers.insert(id, Pt2D::center(&r.osm_center_points));
|
||||
for pt in &r.osm_center_points {
|
||||
pt_to_intersection.insert(pt.to_hashable(), id);
|
||||
}
|
||||
|
||||
false
|
||||
} else {
|
||||
true
|
||||
input.roads.retain(|(id, pts, tags)| {
|
||||
if should_collapse_roundabout(pts, tags) {
|
||||
info!("Collapsing tiny roundabout {}", id);
|
||||
// Arbitrarily use the first node's ID
|
||||
let id = input.osm_node_ids[&pts[0].to_hashable()];
|
||||
roundabout_centers.insert(id, Pt2D::center(pts));
|
||||
for pt in pts {
|
||||
pt_to_intersection.insert(pt.to_hashable(), id);
|
||||
}
|
||||
});
|
||||
input.roads = roads;
|
||||
}
|
||||
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
let mut counts_per_pt = Counter::new();
|
||||
for (_, r) in &input.roads {
|
||||
for (idx, raw_pt) in r.osm_center_points.iter().enumerate() {
|
||||
for (_, pts, _) in &input.roads {
|
||||
for (idx, raw_pt) in pts.iter().enumerate() {
|
||||
let pt = raw_pt.to_hashable();
|
||||
let count = counts_per_pt.inc(pt);
|
||||
|
||||
// All start and endpoints of ways are also intersections.
|
||||
if count == 2 || idx == 0 || idx == r.osm_center_points.len() - 1 {
|
||||
if count == 2 || idx == 0 || idx == pts.len() - 1 {
|
||||
if let Entry::Vacant(e) = pt_to_intersection.entry(pt) {
|
||||
let id = input.osm_node_ids[&pt];
|
||||
e.insert(id);
|
||||
@ -82,27 +78,25 @@ pub fn split_up_roads(map: &mut RawMap, mut input: OsmExtract, timer: &mut Timer
|
||||
|
||||
// Now actually split up the roads based on the intersections
|
||||
timer.start_iter("split roads", input.roads.len());
|
||||
for (osm_way_id, orig_road) in &input.roads {
|
||||
for (osm_way_id, orig_pts, orig_tags) in &input.roads {
|
||||
timer.next();
|
||||
let mut r = orig_road.clone();
|
||||
let mut tags = orig_tags.clone();
|
||||
let mut pts = Vec::new();
|
||||
let endpt1 = pt_to_intersection[&orig_road.osm_center_points[0].to_hashable()];
|
||||
let endpt2 = pt_to_intersection[&orig_road.osm_center_points.last().unwrap().to_hashable()];
|
||||
let endpt1 = pt_to_intersection[&orig_pts[0].to_hashable()];
|
||||
let endpt2 = pt_to_intersection[&orig_pts.last().unwrap().to_hashable()];
|
||||
let mut i1 = endpt1;
|
||||
|
||||
for pt in &orig_road.osm_center_points {
|
||||
for pt in orig_pts {
|
||||
pts.push(*pt);
|
||||
if pts.len() == 1 {
|
||||
continue;
|
||||
}
|
||||
if let Some(i2) = pt_to_intersection.get(&pt.to_hashable()) {
|
||||
if i1 == endpt1 {
|
||||
r.osm_tags
|
||||
.insert(osm::ENDPT_BACK.to_string(), "true".to_string());
|
||||
tags.insert(osm::ENDPT_BACK.to_string(), "true".to_string());
|
||||
}
|
||||
if *i2 == endpt2 {
|
||||
r.osm_tags
|
||||
.insert(osm::ENDPT_FWD.to_string(), "true".to_string());
|
||||
tags.insert(osm::ENDPT_FWD.to_string(), "true".to_string());
|
||||
}
|
||||
let id = OriginalRoad {
|
||||
osm_way_id: *osm_way_id,
|
||||
@ -117,11 +111,12 @@ pub fn split_up_roads(map: &mut RawMap, mut input: OsmExtract, timer: &mut Timer
|
||||
}
|
||||
}
|
||||
|
||||
r.osm_center_points = simplify_linestring(std::mem::take(&mut pts));
|
||||
let osm_center_pts = simplify_linestring(std::mem::take(&mut pts));
|
||||
map.roads
|
||||
.insert(id, RawRoad::new(osm_center_pts, tags, &map.config));
|
||||
|
||||
// Start a new road
|
||||
map.roads.insert(id, r.clone());
|
||||
r.osm_tags.remove(osm::ENDPT_FWD);
|
||||
r.osm_tags.remove(osm::ENDPT_BACK);
|
||||
tags = orig_tags.clone();
|
||||
i1 = *i2;
|
||||
pts.push(*pt);
|
||||
}
|
||||
@ -244,9 +239,8 @@ fn simplify_linestring(pts: Vec<Pt2D>) -> Vec<Pt2D> {
|
||||
/// Note https://www.openstreetmap.org/way/394991047 is an example of something that shouldn't get
|
||||
/// modified. The only distinction, currently, is length -- but I'd love a better definition.
|
||||
/// Possibly the number of connecting roads.
|
||||
fn should_collapse_roundabout(r: &RawRoad) -> bool {
|
||||
r.osm_tags
|
||||
.is_any("junction", vec!["roundabout", "circular"])
|
||||
&& r.osm_center_points[0] == *r.osm_center_points.last().unwrap()
|
||||
&& r.length() < Distance::meters(50.0)
|
||||
fn should_collapse_roundabout(pts: &[Pt2D], tags: &Tags) -> bool {
|
||||
tags.is_any("junction", vec!["roundabout", "circular"])
|
||||
&& pts[0] == *pts.last().unwrap()
|
||||
&& PolyLine::unchecked_new(pts.to_vec()).length() < Distance::meters(50.0)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user