mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
match transit stops to side of the road based on the orientation of the points in the route. don't use this just yet...
not regerating yet either
This commit is contained in:
parent
94f83dcc6a
commit
6c525d625d
@ -177,20 +177,20 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
|
||||
}
|
||||
|
||||
let mut borders: Vec<OriginalIntersection> = Vec::new();
|
||||
for pt in r.all_pts.drain(..) {
|
||||
if let Some(i) = map.intersections.get(&pt) {
|
||||
for pt in &r.all_pts {
|
||||
if let Some(i) = map.intersections.get(pt) {
|
||||
if i.intersection_type == IntersectionType::Border {
|
||||
borders.push(pt);
|
||||
borders.push(*pt);
|
||||
}
|
||||
}
|
||||
if let Some(i) = extra_borders.get(&pt) {
|
||||
if let Some(i) = extra_borders.get(pt) {
|
||||
borders.push(*i);
|
||||
}
|
||||
}
|
||||
|
||||
// Guess which border is for the beginning and end of the route.
|
||||
let start_i = map.closest_intersection(r.stops[0].vehicle_pos);
|
||||
let end_i = map.closest_intersection(r.stops.last().unwrap().vehicle_pos);
|
||||
let start_i = map.closest_intersection(r.stops[0].vehicle_pos.1);
|
||||
let end_i = map.closest_intersection(r.stops.last().unwrap().vehicle_pos.1);
|
||||
let mut best_start: Option<(OriginalIntersection, Distance)> = None;
|
||||
let mut best_end: Option<(OriginalIntersection, Distance)> = None;
|
||||
for i in borders {
|
||||
|
@ -5,7 +5,8 @@ use abstutil::{retain_btreemap, Tags, Timer};
|
||||
use geom::{HashablePt2D, PolyLine, Polygon, Pt2D, Ring};
|
||||
use kml::{ExtraShape, ExtraShapes};
|
||||
use map_model::raw::{
|
||||
OriginalBuilding, RawArea, RawBuilding, RawMap, RawParkingLot, RawRoad, RestrictionType,
|
||||
OriginalBuilding, OriginalIntersection, RawArea, RawBuilding, RawMap, RawParkingLot, RawRoad,
|
||||
RestrictionType,
|
||||
};
|
||||
use map_model::{osm, AreaType};
|
||||
use osm::{NodeID, OsmID, RelationID, WayID};
|
||||
@ -185,7 +186,7 @@ pub fn extract_osm(map: &mut RawMap, opts: &Options, timer: &mut Timer) -> OsmEx
|
||||
|
||||
let mut amenity_areas: Vec<(String, String, Polygon)> = Vec::new();
|
||||
// Vehicle position (stop) -> pedestrian position (platform)
|
||||
let mut stop_areas: Vec<(Pt2D, Pt2D)> = Vec::new();
|
||||
let mut stop_areas: Vec<((OriginalIntersection, Pt2D), Pt2D)> = Vec::new();
|
||||
|
||||
// TODO Fill this out in a separate loop to keep a mutable borrow short. Maybe do this in
|
||||
// reader, or stop doing this entirely.
|
||||
@ -305,7 +306,7 @@ pub fn extract_osm(map: &mut RawMap, opts: &Options, timer: &mut Timer) -> OsmEx
|
||||
if let OsmID::Node(n) = member {
|
||||
let pt = doc.nodes[n].pt;
|
||||
if role == "stop" {
|
||||
stops.push(pt);
|
||||
stops.push((OriginalIntersection { osm_node_id: *n }, pt));
|
||||
} else if role == "platform" {
|
||||
platform = Some(pt);
|
||||
}
|
||||
|
@ -72,13 +72,28 @@ pub fn convert(opts: Options, timer: &mut abstutil::Timer) -> RawMap {
|
||||
}
|
||||
|
||||
let extract = extract::extract_osm(&mut map, &opts, timer);
|
||||
let amenities = split_ways::split_up_roads(&mut map, extract, timer);
|
||||
let (amenities, pt_to_road) = split_ways::split_up_roads(&mut map, extract, timer);
|
||||
clip::clip_map(&mut map, timer);
|
||||
|
||||
// Need to do a first pass of removing cul-de-sacs here, or we wind up with loop PolyLines when
|
||||
// doing the parking hint matching.
|
||||
abstutil::retain_btreemap(&mut map.roads, |r, _| r.i1 != r.i2);
|
||||
|
||||
let all_routes = map.bus_routes.drain(..).collect::<Vec<_>>();
|
||||
let mut routes = Vec::new();
|
||||
for route in all_routes {
|
||||
let name = format!("{} ({})", route.osm_rel_id, route.full_name);
|
||||
match transit::snap_bus_stops(route, &map, &pt_to_road) {
|
||||
Ok(r) => {
|
||||
routes.push(r);
|
||||
}
|
||||
Err(err) => {
|
||||
timer.error(format!("Skipping {}: {}", name, err));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.bus_routes = routes;
|
||||
|
||||
use_amenities(&mut map, amenities, timer);
|
||||
|
||||
parking::apply_parking(&mut map, &opts, timer);
|
||||
|
@ -5,12 +5,16 @@ use map_model::raw::{OriginalIntersection, OriginalRoad, RawIntersection, RawMap
|
||||
use map_model::{osm, IntersectionType};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Returns amenities
|
||||
// Returns amenities and a mapping of all points to split road. (Some internal points on roads are
|
||||
// removed, so this mapping isn't redundant.)
|
||||
pub fn split_up_roads(
|
||||
map: &mut RawMap,
|
||||
mut input: OsmExtract,
|
||||
timer: &mut Timer,
|
||||
) -> Vec<(Pt2D, String, String)> {
|
||||
) -> (
|
||||
Vec<(Pt2D, String, String)>,
|
||||
HashMap<HashablePt2D, OriginalRoad>,
|
||||
) {
|
||||
timer.start("splitting up roads");
|
||||
|
||||
let mut pt_to_intersection: HashMap<HashablePt2D, OriginalIntersection> = HashMap::new();
|
||||
@ -48,6 +52,8 @@ pub fn split_up_roads(
|
||||
);
|
||||
}
|
||||
|
||||
let mut pt_to_road: HashMap<HashablePt2D, OriginalRoad> = HashMap::new();
|
||||
|
||||
// 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 {
|
||||
@ -72,16 +78,18 @@ pub fn split_up_roads(
|
||||
r.osm_tags
|
||||
.insert(osm::ENDPT_FWD.to_string(), "true".to_string());
|
||||
}
|
||||
let id = OriginalRoad {
|
||||
osm_way_id: *osm_way_id,
|
||||
i1,
|
||||
i2: *i2,
|
||||
};
|
||||
for pt in &pts {
|
||||
pt_to_road.insert(pt.to_hashable(), id);
|
||||
}
|
||||
|
||||
r.center_points = dedupe_angles(std::mem::replace(&mut pts, Vec::new()));
|
||||
// Start a new road
|
||||
map.roads.insert(
|
||||
OriginalRoad {
|
||||
osm_way_id: *osm_way_id,
|
||||
i1,
|
||||
i2: *i2,
|
||||
},
|
||||
r.clone(),
|
||||
);
|
||||
map.roads.insert(id, r.clone());
|
||||
r.osm_tags.remove(osm::ENDPT_FWD);
|
||||
r.osm_tags.remove(osm::ENDPT_BACK);
|
||||
i1 = *i2;
|
||||
@ -188,7 +196,7 @@ pub fn split_up_roads(
|
||||
}
|
||||
|
||||
timer.stop("splitting up roads");
|
||||
input.amenities
|
||||
(input.amenities, pt_to_road)
|
||||
}
|
||||
|
||||
// TODO Consider doing this in PolyLine::new always. extend() there does this too.
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::reader::{Document, Relation};
|
||||
use abstutil::Timer;
|
||||
use geom::{Polygon, Pt2D};
|
||||
use geom::{HashablePt2D, Polygon, Pt2D};
|
||||
use map_model::osm::{NodeID, OsmID, RelationID, WayID};
|
||||
use map_model::raw::{OriginalIntersection, RawBusRoute, RawBusStop};
|
||||
use map_model::raw::{OriginalIntersection, OriginalRoad, RawBusRoute, RawBusStop, RawMap};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn extract_route(
|
||||
@ -47,7 +47,8 @@ pub fn extract_route(
|
||||
.get("name")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format!("stop #{}", stops.len() + 1)),
|
||||
vehicle_pos: node.pt,
|
||||
vehicle_pos: (OriginalIntersection { osm_node_id: *n }, node.pt),
|
||||
matched_road: None,
|
||||
ped_pos: None,
|
||||
});
|
||||
}
|
||||
@ -89,7 +90,7 @@ pub fn extract_route(
|
||||
let all_pts: Vec<OriginalIntersection> = match glue_route(all_ways, doc) {
|
||||
Ok(nodes) => nodes
|
||||
.into_iter()
|
||||
.map(|n| OriginalIntersection { osm_node_id: n })
|
||||
.map(|osm_node_id| OriginalIntersection { osm_node_id })
|
||||
.collect(),
|
||||
Err(err) => {
|
||||
timer.error(format!(
|
||||
@ -106,7 +107,7 @@ pub fn extract_route(
|
||||
let mut keep_stops = Vec::new();
|
||||
let orig_num = stops.len();
|
||||
for stop in stops {
|
||||
if boundary.contains_pt(stop.vehicle_pos) {
|
||||
if boundary.contains_pt(stop.vehicle_pos.1) {
|
||||
keep_stops.push(stop);
|
||||
} else {
|
||||
if !keep_stops.is_empty() {
|
||||
@ -184,7 +185,78 @@ fn glue_route(all_ways: Vec<WayID>, doc: &Document) -> Result<Vec<NodeID>, Strin
|
||||
extra = nodes2;
|
||||
}
|
||||
// And the last lil bit
|
||||
if nodes.is_empty() {
|
||||
return Err(format!("empty? ways: {:?}", all_ways));
|
||||
}
|
||||
assert_eq!(nodes.pop().unwrap(), extra[0]);
|
||||
nodes.extend(extra);
|
||||
Ok(nodes)
|
||||
}
|
||||
|
||||
pub fn snap_bus_stops(
|
||||
mut route: RawBusRoute,
|
||||
raw: &RawMap,
|
||||
pt_to_road: &HashMap<HashablePt2D, OriginalRoad>,
|
||||
) -> Result<RawBusRoute, String> {
|
||||
// For every stop, figure out what road segment and direction it matches up to.
|
||||
for stop in &mut route.stops {
|
||||
// TODO Handle this, example https://www.openstreetmap.org/node/4560936658
|
||||
if raw.intersections.contains_key(&stop.vehicle_pos.0) {
|
||||
return Err(format!(
|
||||
"{} has a stop {} right at an intersection, skipping",
|
||||
route.osm_rel_id, stop.vehicle_pos.0.osm_node_id
|
||||
));
|
||||
}
|
||||
|
||||
let idx_in_route = route
|
||||
.all_pts
|
||||
.iter()
|
||||
.position(|pt| stop.vehicle_pos.0 == *pt)
|
||||
.unwrap();
|
||||
// Scan backwards and forwards in the route for the nearest intersections.
|
||||
// TODO Express better with iterators
|
||||
let mut i1 = None;
|
||||
for idx in (0..=idx_in_route).rev() {
|
||||
let i = route.all_pts[idx];
|
||||
if raw.intersections.contains_key(&i) {
|
||||
i1 = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut i2 = None;
|
||||
for idx in idx_in_route..route.all_pts.len() {
|
||||
let i = route.all_pts[idx];
|
||||
if raw.intersections.contains_key(&i) {
|
||||
i2 = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let road = pt_to_road[&stop.vehicle_pos.1.to_hashable()];
|
||||
let i1 = i1.unwrap();
|
||||
let i2 = i2.unwrap();
|
||||
let fwds = if road.i1 == i1 && road.i2 == i2 {
|
||||
true
|
||||
} else if road.i1 == i2 && road.i2 == i1 {
|
||||
false
|
||||
} else {
|
||||
return Err(format!(
|
||||
"Can't figure out where {} is along route. {:?}, {:?}. {} of {}",
|
||||
stop.vehicle_pos.0.osm_node_id,
|
||||
i1,
|
||||
i2,
|
||||
idx_in_route,
|
||||
route.all_pts.len()
|
||||
));
|
||||
};
|
||||
|
||||
stop.matched_road = Some((road, fwds));
|
||||
if false {
|
||||
println!(
|
||||
"{} matched to {}, fwds={}",
|
||||
stop.vehicle_pos.0.osm_node_id, road, fwds
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(route)
|
||||
}
|
||||
|
@ -197,9 +197,9 @@ impl Matcher {
|
||||
for r in routes {
|
||||
for stop in &r.stops {
|
||||
if r.is_bus {
|
||||
lookup_bus_pts.insert(stop.vehicle_pos.to_hashable());
|
||||
lookup_bus_pts.insert(stop.vehicle_pos.1.to_hashable());
|
||||
} else {
|
||||
lookup_light_rail_pts.insert(stop.vehicle_pos.to_hashable());
|
||||
lookup_light_rail_pts.insert(stop.vehicle_pos.1.to_hashable());
|
||||
}
|
||||
if let Some(pt) = stop.ped_pos {
|
||||
lookup_sidewalk_pts.insert(pt.to_hashable());
|
||||
@ -258,9 +258,9 @@ impl Matcher {
|
||||
.ok_or_else(|| format!("sidewalk for light rail didnt match: {}", sidewalk_pt))?;
|
||||
let driving_pos = *self
|
||||
.light_rail_pts
|
||||
.get(&stop.vehicle_pos.to_hashable())
|
||||
.get(&stop.vehicle_pos.1.to_hashable())
|
||||
.ok_or_else(|| {
|
||||
format!("vehicle for light rail didnt match: {}", stop.vehicle_pos)
|
||||
format!("vehicle for light rail didnt match: {}", stop.vehicle_pos.0)
|
||||
})?;
|
||||
return Ok((sidewalk_pos, driving_pos));
|
||||
}
|
||||
@ -278,8 +278,8 @@ impl Matcher {
|
||||
// rightmost driving/bus lane.
|
||||
let orig_driving_pos = *self
|
||||
.bus_pts
|
||||
.get(&stop.vehicle_pos.to_hashable())
|
||||
.ok_or("vehicle for bus didnt match")?;
|
||||
.get(&stop.vehicle_pos.1.to_hashable())
|
||||
.ok_or_else(|| format!("vehicle for bus didnt match: {}", stop.vehicle_pos.0))?;
|
||||
let sidewalk = map
|
||||
.get_parent(orig_driving_pos.lane())
|
||||
.find_closest_lane(
|
||||
|
@ -463,14 +463,18 @@ pub struct RawBusRoute {
|
||||
pub stops: Vec<RawBusStop>,
|
||||
pub border_start: Option<OriginalIntersection>,
|
||||
pub border_end: Option<OriginalIntersection>,
|
||||
// Temporarily plumbed along
|
||||
// This is guaranteed to be in order and contiguous. These're ALL nodes, not just
|
||||
// intersections.
|
||||
pub all_pts: Vec<OriginalIntersection>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RawBusStop {
|
||||
pub name: String,
|
||||
pub vehicle_pos: Pt2D,
|
||||
// Probably not an intersection, but this type is more convenient.
|
||||
pub vehicle_pos: (OriginalIntersection, Pt2D),
|
||||
// Guaranteed to be filled out when RawMap is fully written. True for forwards.
|
||||
pub matched_road: Option<(OriginalRoad, bool)>,
|
||||
// If it's not explicitly mapped, we'll do equiv_pos.
|
||||
pub ped_pos: Option<Pt2D>,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user