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