-
-
Notifications
You must be signed in to change notification settings - Fork 353
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Populating the map_model transit representation from the raw GTFS data.
#372 (WIP)
- Loading branch information
1 parent
98557bd
commit 881da63
Showing
3 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
use std::collections::{HashSet, HashMap}; | ||
|
||
use anyhow::Result; | ||
|
||
use geom::{Distance, FindClosest, HashablePt2D}; | ||
use abstutil::Timer; | ||
|
||
use crate::{TransitStopID, LaneID, TransitRouteID, TransitStop, TransitRoute, PathConstraints, Map}; | ||
use crate::raw::{RawTransitRoute, RawMap}; | ||
use crate::make::match_points_to_lanes; | ||
|
||
pub fn finalize_transit(map: &mut Map, raw: &RawMap, timer: &mut Timer) { | ||
// Snap stops to sidewalks and driving lanes, similar to buildings | ||
let mut query: HashSet<HashablePt2D> = HashSet::new(); | ||
for stop in raw.transit_stops.values() { | ||
query.insert(stop.position.to_hashable()); | ||
} | ||
let sidewalk_buffer = Distance::meters(7.5); | ||
let sidewalk_pts = match_points_to_lanes( | ||
map, | ||
query, | ||
|l| l.is_walkable(), | ||
// Stops can be very close to intersections | ||
Distance::ZERO, | ||
// Stops shouldn't be far from sidewalks | ||
Distance::meters(3.0), | ||
timer, | ||
); | ||
|
||
// Create all stops | ||
let mut gtfs_to_stop_id: HashMap<String, TransitStopID> = HashMap::new(); | ||
for stop in raw.transit_stops.values() { | ||
// TODO How do we know this here? | ||
let vehicle = PathConstraints::Bus; | ||
if let Some(sidewalk_pos) = sidewalk_pts.get(&stop.position.to_hashable()) { | ||
let sidewalk_lane = sidewalk_pos.lane(); | ||
if let Some(driving_pos) = map | ||
.get_parent(sidewalk_lane) | ||
.find_closest_lane(sidewalk_lane, |l| vehicle.can_use(l, map)) | ||
.map(|l| sidewalk_pos.equiv_pos(l, map)) | ||
{ | ||
let id = TransitStopID { | ||
sidewalk: sidewalk_lane, | ||
idx: map.get_l(sidewalk_lane).transit_stops.len(), | ||
}; | ||
map.mut_lane(sidewalk_lane).transit_stops.insert(id); | ||
map.transit_stops.insert(id, TransitStop { | ||
id, | ||
name: stop.name.clone(), | ||
gtfs_id: stop.gtfs_id.clone(), | ||
driving_pos, | ||
sidewalk_pos: *sidewalk_pos, | ||
is_train_stop: vehicle == PathConstraints::Train, | ||
}); | ||
gtfs_to_stop_id.insert(stop.gtfs_id.clone(), id); | ||
} | ||
} | ||
} | ||
|
||
let snapper = BorderSnapper::new(map); | ||
for route in &raw.transit_routes { | ||
if let Err(err) = setup_route(route, map, >fs_to_stop_id, &snapper) { | ||
warn!("Couldn't snap route {}: {}", route.gtfs_id, err); | ||
} | ||
} | ||
|
||
// TODO Clean up unused stops; maybe one of the routes didn't work. Re-map IDs... | ||
} | ||
|
||
struct BorderSnapper { | ||
bus_incoming_borders: FindClosest<LaneID>, | ||
bus_outgoing_borders: FindClosest<LaneID>, | ||
train_incoming_borders: FindClosest<LaneID>, | ||
train_outgoing_borders: FindClosest<LaneID>, | ||
} | ||
|
||
impl BorderSnapper { | ||
fn new(map: &Map) -> BorderSnapper { | ||
let mut snapper = BorderSnapper { | ||
bus_incoming_borders: FindClosest::new(map.get_bounds()), | ||
bus_outgoing_borders: FindClosest::new(map.get_bounds()), | ||
train_incoming_borders: FindClosest::new(map.get_bounds()), | ||
train_outgoing_borders: FindClosest::new(map.get_bounds()), | ||
}; | ||
for i in map.all_incoming_borders() { | ||
for l in i.get_outgoing_lanes(map, PathConstraints::Bus) { | ||
snapper.bus_incoming_borders.add(l, &vec![map.get_l(l).first_pt()]); | ||
} | ||
for l in i.get_outgoing_lanes(map, PathConstraints::Train) { | ||
snapper.train_incoming_borders.add(l, &vec![map.get_l(l).first_pt()]); | ||
} | ||
} | ||
for i in map.all_outgoing_borders() { | ||
for l in i.get_incoming_lanes(map, PathConstraints::Bus) { | ||
snapper.bus_outgoing_borders.add(l, &vec![map.get_l(l).last_pt()]); | ||
} | ||
for l in i.get_incoming_lanes(map, PathConstraints::Train) { | ||
snapper.train_outgoing_borders.add(l, &vec![map.get_l(l).last_pt()]); | ||
} | ||
} | ||
snapper | ||
} | ||
} | ||
|
||
fn setup_route(route: &RawTransitRoute, map: &mut Map, gtfs_to_stop_id: &HashMap<String, TransitStopID>, snapper: &BorderSnapper) -> Result<()> { | ||
let start = if map.boundary_polygon.contains_pt(route.shape.first_pt()) { | ||
let stop_id = gtfs_to_stop_id.get(&route.stops[0])?; | ||
map.get_bs(stop_id).driving_pos.lane() | ||
} else { | ||
// Find the first time the route shape hits the map boundary | ||
let entry_pt = route.shape.first_intersection(&map.boundary_polygon)?; | ||
// Snap that to a border | ||
let borders = if route.route_type == PathConstraints::Bus { | ||
&snapper.bus_incoming_borders | ||
} else { | ||
&snapper.train_incoming_borders | ||
}; | ||
borders.closest_pt(entry_pt, Distance::meters(10.0))?.0 | ||
}; | ||
|
||
let end_border = if map.boundary_polygon.contains_pt(route.shape.last_pt()) { | ||
None | ||
} else { | ||
// Find the last time the route shape hits the map boundary | ||
let entry_pt = route.shape.reversed().first_intersection(&map.boundary_polygon)?; | ||
// Snap that to a border | ||
let borders = if route.route_type == PathConstraints::Bus { | ||
&snapper.bus_outgoing_borders_ | ||
} else { | ||
&snapper.train_outgoing_borders_ | ||
}; | ||
Some(borders.closest_pt(entry_pt, Distance::meters(10.0))?.0) | ||
}; | ||
|
||
|
||
bail!("nah"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters