raw_map/
lib.rs

1//! The convert_osm crate produces a RawMap from OSM and other data. Storing this intermediate
2//! structure is useful to iterate quickly on parts of the map importing pipeline without having to
3//! constantly read .osm files, and to visualize the intermediate state with map_editor.
4
5use std::collections::BTreeMap;
6
7use osm2streets::{osm, IntersectionID, RoadID, StreetNetwork};
8use popgetter::CensusZone;
9use serde::{Deserialize, Serialize};
10
11use abstio::{CityName, MapName};
12use abstutil::{
13    deserialize_btreemap, deserialize_multimap, serialize_btreemap, serialize_multimap, MultiMap,
14    Tags,
15};
16use geom::{Distance, PolyLine, Polygon, Pt2D};
17
18pub use self::types::{Amenity, AmenityType, AreaType};
19
20mod types;
21
22#[derive(Serialize, Deserialize)]
23pub struct RawMap {
24    pub name: MapName,
25    pub streets: StreetNetwork,
26    #[serde(
27        serialize_with = "serialize_btreemap",
28        deserialize_with = "deserialize_btreemap"
29    )]
30    pub buildings: BTreeMap<osm::OsmID, RawBuilding>,
31    pub areas: Vec<RawArea>,
32    pub parking_lots: Vec<RawParkingLot>,
33    pub parking_aisles: Vec<(osm::WayID, Vec<Pt2D>)>,
34    pub transit_routes: Vec<RawTransitRoute>,
35    pub census_zones: Vec<(Polygon, CensusZone)>,
36    #[serde(
37        serialize_with = "serialize_btreemap",
38        deserialize_with = "deserialize_btreemap"
39    )]
40    pub transit_stops: BTreeMap<String, RawTransitStop>,
41    /// Per road, what bus routes run along it?
42    ///
43    /// This is scraped from OSM relations for every map, unlike the more detailed `transit_routes`
44    /// above, which come from GTFS only for a few maps. This is used only to identify roads part
45    /// of bus routes. It's best-effort and not robust to edits or transformations.
46    #[serde(
47        serialize_with = "serialize_multimap",
48        deserialize_with = "deserialize_multimap"
49    )]
50    pub bus_routes_on_roads: MultiMap<osm::WayID, String>,
51    #[serde(
52        serialize_with = "serialize_btreemap",
53        deserialize_with = "deserialize_btreemap"
54    )]
55    pub osm_tags: BTreeMap<osm::WayID, Tags>,
56
57    #[serde(
58        serialize_with = "serialize_btreemap",
59        deserialize_with = "deserialize_btreemap"
60    )]
61    pub extra_road_data: BTreeMap<RoadID, ExtraRoadData>,
62    #[serde(
63        serialize_with = "serialize_btreemap",
64        deserialize_with = "deserialize_btreemap"
65    )]
66    pub elevation_per_intersection: BTreeMap<IntersectionID, Distance>,
67    pub extra_pois: Vec<ExtraPOI>,
68}
69
70impl RawMap {
71    pub fn blank(name: MapName) -> RawMap {
72        RawMap {
73            name,
74            streets: StreetNetwork::blank(),
75            buildings: BTreeMap::new(),
76            areas: Vec::new(),
77            parking_lots: Vec::new(),
78            parking_aisles: Vec::new(),
79            transit_routes: Vec::new(),
80            census_zones: Vec::new(),
81            transit_stops: BTreeMap::new(),
82            bus_routes_on_roads: MultiMap::new(),
83            osm_tags: BTreeMap::new(),
84            extra_road_data: BTreeMap::new(),
85            elevation_per_intersection: BTreeMap::new(),
86            extra_pois: Vec::new(),
87        }
88    }
89
90    pub fn save(&self) {
91        abstio::write_binary(abstio::path_raw_map(&self.name), self)
92    }
93
94    pub fn get_city_name(&self) -> &CityName {
95        &self.name.city
96    }
97
98    // Only returns tags for one of the way IDs arbitrarily!
99    pub fn road_to_osm_tags(&self, id: RoadID) -> Option<&Tags> {
100        let way = self.streets.roads[&id].osm_ids.get(0)?;
101        self.osm_tags.get(&way)
102    }
103}
104
105#[derive(Clone, Debug, Serialize, Deserialize)]
106pub struct RawBuilding {
107    pub polygon: Polygon,
108    pub osm_tags: Tags,
109    pub public_garage_name: Option<String>,
110    pub num_parking_spots: usize,
111    pub amenities: Vec<Amenity>,
112}
113
114#[derive(Clone, Debug, Serialize, Deserialize)]
115pub struct RawArea {
116    pub area_type: AreaType,
117    pub polygon: Polygon,
118    pub osm_tags: Tags,
119    pub osm_id: osm::OsmID,
120}
121
122#[derive(Clone, Debug, Serialize, Deserialize)]
123pub struct RawParkingLot {
124    pub osm_id: osm::OsmID,
125    pub polygon: Polygon,
126    pub osm_tags: Tags,
127}
128
129#[derive(Clone, Debug, Serialize, Deserialize)]
130pub struct RawTransitRoute {
131    pub long_name: String,
132    pub short_name: String,
133    pub gtfs_id: String,
134    /// This may begin and/or end inside or outside the map boundary.
135    pub shape: PolyLine,
136    /// Entries into transit_stops
137    pub stops: Vec<String>,
138    pub route_type: RawTransitType,
139    // TODO Schedule
140}
141
142#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
143pub enum RawTransitType {
144    Bus,
145    Train,
146}
147
148#[derive(Clone, Debug, Serialize, Deserialize)]
149pub struct RawTransitStop {
150    pub gtfs_id: String,
151    /// Only stops within a map's boundary are kept
152    pub position: Pt2D,
153    pub name: String,
154}
155
156/// Classifies pedestrian and cyclist crossings. Note lots of detail is missing.
157#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
158pub enum CrossingType {
159    /// Part of some traffic signal
160    Signalized,
161    /// Not part of a traffic signal
162    Unsignalized,
163}
164
165/// Extra data associated with one Road
166#[derive(Clone, Debug, Serialize, Deserialize)]
167pub struct ExtraRoadData {
168    pub percent_incline: f64,
169    /// Is there a tagged crosswalk near each end of the road?
170    pub crosswalk_forward: bool,
171    pub crosswalk_backward: bool,
172    // TODO Preserving these two across transformations (especially merging dual carriageways!)
173    // could be really hard. It might be better to split the road into two pieces to match the more
174    // often used OSM style.
175    /// Barrier nodes along this road's original center line.
176    pub barrier_nodes: Vec<Pt2D>,
177    /// Crossing nodes along this road's original center line.
178    pub crossing_nodes: Vec<(Pt2D, CrossingType)>,
179}
180
181impl ExtraRoadData {
182    pub fn default() -> Self {
183        Self {
184            percent_incline: 0.0,
185            // Start assuming there's a crosswalk everywhere, and maybe filter it down later
186            crosswalk_forward: true,
187            crosswalk_backward: true,
188            barrier_nodes: Vec::new(),
189            crossing_nodes: Vec::new(),
190        }
191    }
192}
193
194/// Extra point-of-interest
195#[derive(Clone, Debug, Serialize, Deserialize)]
196pub struct ExtraPOI {
197    pub pt: Pt2D,
198    pub kind: ExtraPOIType,
199}
200
201#[derive(Clone, Debug, Serialize, Deserialize)]
202pub enum ExtraPOIType {
203    LondonUndergroundStation(String),
204    NationalRailStation(String),
205}