synthpop/
borders.rs

1use geom::{LonLat, Pt2D};
2use map_model::osm::RoadRank;
3use map_model::{Intersection, IntersectionID, Map, PathConstraints};
4
5use crate::TripMode;
6
7/// Lists all border intersections of the map, broken down by mode and whether they support
8/// incoming or outgoing traffic.
9#[derive(Clone)]
10pub struct MapBorders {
11    pub incoming_walking: Vec<MapBorder>,
12    pub incoming_driving: Vec<MapBorder>,
13    pub incoming_biking: Vec<MapBorder>,
14    pub outgoing_walking: Vec<MapBorder>,
15    pub outgoing_driving: Vec<MapBorder>,
16    pub outgoing_biking: Vec<MapBorder>,
17}
18
19#[derive(Clone)]
20pub struct MapBorder {
21    pub i: IntersectionID,
22    pub pos: Pt2D,
23    pub gps_pos: LonLat,
24    /// Based on the classification of the connecting road, a weight for how likely this border is
25    /// to be used for traffic.
26    pub weight: usize,
27}
28
29impl MapBorders {
30    pub fn new(map: &Map) -> MapBorders {
31        let incoming_walking = map
32            .all_incoming_borders()
33            .into_iter()
34            .filter(|i| {
35                !i.get_outgoing_lanes(map, PathConstraints::Pedestrian)
36                    .is_empty()
37            })
38            .map(|i| MapBorder::new(map, i))
39            .collect::<Vec<_>>();
40        let incoming_driving = map
41            .all_incoming_borders()
42            .into_iter()
43            .filter(|i| !i.get_outgoing_lanes(map, PathConstraints::Car).is_empty())
44            .map(|i| MapBorder::new(map, i))
45            .collect::<Vec<_>>();
46        let incoming_biking = map
47            .all_incoming_borders()
48            .into_iter()
49            .filter(|i| !i.get_outgoing_lanes(map, PathConstraints::Bike).is_empty())
50            .map(|i| MapBorder::new(map, i))
51            .collect::<Vec<_>>();
52        let outgoing_walking = map
53            .all_outgoing_borders()
54            .into_iter()
55            .filter(|i| {
56                !i.get_incoming_lanes(map, PathConstraints::Pedestrian)
57                    .is_empty()
58            })
59            .map(|i| MapBorder::new(map, i))
60            .collect::<Vec<_>>();
61        let outgoing_driving = map
62            .all_outgoing_borders()
63            .into_iter()
64            .filter(|i| !i.get_incoming_lanes(map, PathConstraints::Car).is_empty())
65            .map(|i| MapBorder::new(map, i))
66            .collect::<Vec<_>>();
67        let outgoing_biking = map
68            .all_outgoing_borders()
69            .into_iter()
70            .filter(|i| !i.get_incoming_lanes(map, PathConstraints::Bike).is_empty())
71            .map(|i| MapBorder::new(map, i))
72            .collect::<Vec<_>>();
73        MapBorders {
74            incoming_walking,
75            incoming_driving,
76            incoming_biking,
77            outgoing_walking,
78            outgoing_driving,
79            outgoing_biking,
80        }
81    }
82
83    /// Returns the (incoming, outgoing) borders for the specififed mode.
84    pub fn for_mode(&self, mode: TripMode) -> (&Vec<MapBorder>, &Vec<MapBorder>) {
85        match mode {
86            TripMode::Walk | TripMode::Transit => (&self.incoming_walking, &self.outgoing_walking),
87            TripMode::Drive => (&self.incoming_driving, &self.outgoing_driving),
88            TripMode::Bike => (&self.incoming_biking, &self.outgoing_biking),
89        }
90    }
91}
92
93impl MapBorder {
94    fn new(map: &Map, i: &Intersection) -> Self {
95        // TODO Mostly untuned, and agnostic to TripMode
96        let road = map.get_r(*i.roads.iter().next().unwrap());
97        let mut weight = match road.get_rank() {
98            RoadRank::Local => 3,
99            RoadRank::Arterial => 5,
100            RoadRank::Highway => 8,
101        };
102        // TODO We should consider more values for RoadRank
103        if road.is_service() {
104            weight = 1;
105        }
106
107        let pos = i.polygon.center();
108        Self {
109            i: i.id,
110            pos,
111            gps_pos: pos.to_gps(map.get_gps_bounds()),
112            weight,
113        }
114    }
115}