1#![allow(clippy::type_complexity)]
6
7#[macro_use]
8extern crate anyhow;
9#[macro_use]
10extern crate log;
11
12use structopt::StructOpt;
13
14use abstio::{CityName, MapName};
15use abstutil::Timer;
16use map_model::RawToMapOptions;
17
18pub use self::configuration::ImporterConfiguration;
19pub use self::pick_geofabrik::pick_geofabrik;
20pub use utils::osmium;
21
22mod berlin;
23mod configuration;
24mod map_config;
25mod pick_geofabrik;
26mod seattle;
27mod soundcast;
28mod uk;
29mod utils;
30
31pub async fn regenerate_everything(shard_num: usize, num_shards: usize) {
33 let mut all_cities = CityName::list_all_cities_from_importer_config();
36 all_cities.retain(|x| x != &CityName::seattle());
37 all_cities.insert(0, CityName::seattle());
38
39 let mut timer = Timer::new("regenerate all maps");
40 for (cnt, city) in all_cities.into_iter().enumerate() {
41 if cnt % num_shards == shard_num {
42 let job = Job::full_for_city(city);
43 job.run(&mut timer).await;
44 }
45 }
46}
47
48pub async fn oneshot(
50 osm_path: String,
51 clip: Option<String>,
52 options: convert_osm::Options,
53 create_uk_travel_demand_model: bool,
54 opts: RawToMapOptions,
55) {
56 let mut timer = abstutil::Timer::new("oneshot");
57 println!("- Running convert_osm on {}", osm_path);
58 let name = abstutil::basename(&osm_path);
59 let raw = convert_osm::convert(
60 osm_path,
61 MapName::new("zz", "oneshot", &name),
62 clip,
63 options,
64 &mut timer,
65 );
66 raw.save();
68 let map = map_model::Map::create_from_raw(raw, opts, &mut timer);
69 timer.start("save map");
70 map.save();
71 timer.stop("save map");
72
73 if create_uk_travel_demand_model {
74 timer.start("generating UK travel demand model");
75 uk::generate_scenario(&map, &ImporterConfiguration::load(), &mut timer)
76 .await
77 .unwrap();
78 timer.stop("generating UK travel demand model");
79 }
80
81 println!("{} has been created", map.get_name().path());
82}
83
84#[derive(StructOpt)]
86pub struct Job {
87 #[structopt(long, parse(try_from_str = CityName::parse), default_value = "us/seattle")]
88 pub city: CityName,
89 #[structopt(long = "--raw")]
91 pub osm_to_raw: bool,
92 #[structopt(long = "--map")]
94 pub raw_to_map: bool,
95 #[structopt(long)]
97 pub scenario: bool,
98 #[structopt(long)]
100 pub city_overview: bool,
101
102 #[structopt()]
105 pub only_map: Option<String>,
106
107 #[structopt(flatten)]
108 pub opts: RawToMapOptions,
109}
110
111impl Job {
112 pub fn full_for_city(city: CityName) -> Job {
113 let mut job = Job {
114 city: city,
115 osm_to_raw: true,
116 raw_to_map: true,
117 scenario: false,
118 city_overview: false,
119 only_map: None,
120 opts: RawToMapOptions::default(),
121 };
122 if job.city == CityName::seattle() || job.city.country == "gb" {
124 job.scenario = true;
125 }
126 if job.city == CityName::new("ch", "zurich")
128 || job.city == CityName::new("gb", "leeds")
129 || job.city == CityName::new("gb", "london")
130 || job.city == CityName::new("us", "nyc")
131 || job.city == CityName::new("fr", "charleville_mezieres")
132 || job.city == CityName::new("fr", "paris")
133 || job.city == CityName::new("at", "salzburg")
134 || job.city == CityName::new("ir", "tehran")
135 || job.city == CityName::new("pt", "portugal")
136 {
137 job.city_overview = true;
138 }
139 job
140 }
141
142 pub fn flags(&self) -> Vec<String> {
145 let mut flags = vec![];
147 flags.push(format!("--city={}", self.city.to_path()));
148 if self.osm_to_raw {
149 flags.push("--raw".to_string());
150 }
151 if self.raw_to_map {
152 flags.push("--map".to_string());
153 }
154 if self.scenario {
155 flags.push("--scenario".to_string());
156 }
157 if self.city_overview {
158 flags.push("--city-overview".to_string());
159 }
160 if let Some(ref name) = self.only_map {
161 flags.push(name.clone());
162 }
163 flags
164 }
165
166 pub async fn run(self, timer: &mut Timer<'_>) {
167 if !self.osm_to_raw && !self.raw_to_map && !self.scenario && !self.city_overview {
168 println!(
169 "Nothing to do! Pass some combination of --raw, --map, --scenario, or --city_overview"
170 );
171 std::process::exit(1);
172 }
173
174 let config = ImporterConfiguration::load();
175
176 timer.start(format!("import {}", self.city.describe()));
177 let names = if let Some(n) = self.only_map {
178 println!("- Just working on {}", n);
179 vec![MapName::from_city(&self.city, &n)]
180 } else {
181 println!("- Working on all {} maps", self.city.describe());
182 self.city.list_all_maps_in_city_from_importer_config()
183 };
184
185 let mut built_raw_huge_seattle = false;
188 let mut built_map_huge_seattle = false;
189 let (maybe_popdat, maybe_huge_map, maybe_zoning_parcels) = if self.scenario
190 && self.city == CityName::seattle()
191 {
192 timer.start("ensure_popdat_exists");
193 let (popdat, huge_map) = seattle::ensure_popdat_exists(
194 timer,
195 &config,
196 &mut built_raw_huge_seattle,
197 &mut built_map_huge_seattle,
198 )
199 .await;
200 let shapes: kml::ExtraShapes =
202 abstio::read_binary(CityName::seattle().input_path("zoning_parcels.bin"), timer);
203 timer.stop("ensure_popdat_exists");
204 (Some(popdat), Some(huge_map), Some(shapes))
205 } else {
206 (None, None, None)
207 };
208
209 for name in names {
210 timer.start(name.describe());
211 if self.osm_to_raw
212 && (!built_raw_huge_seattle || name != MapName::seattle("huge_seattle"))
213 {
214 let raw = utils::osm_to_raw(name.clone(), timer, &config).await;
215
216 if name.city == CityName::new("de", "berlin") {
219 berlin::import_extra_data(&raw, &config, timer).await;
220 } else if name == MapName::new("gb", "leeds", "huge") {
221 uk::import_collision_data(&raw, &config, timer).await;
222 } else if name == MapName::new("gb", "london", "camden") {
223 uk::import_collision_data(&raw, &config, timer).await;
224 }
225 }
226
227 let mut maybe_map = if self.raw_to_map {
228 let mut map = if built_map_huge_seattle && name == MapName::seattle("huge_seattle")
229 {
230 map_model::Map::load_synchronously(name.path(), timer)
231 } else {
232 utils::raw_to_map(&name, self.opts.clone(), timer)
233 };
234
235 if name == MapName::new("de", "berlin", "center") {
237 timer.start(format!(
238 "distribute residents from planning areas for {}",
239 name.describe()
240 ));
241 berlin::distribute_residents(&mut map, timer);
242 timer.stop(format!(
243 "distribute residents from planning areas for {}",
244 name.describe()
245 ));
246
247 map.save();
248 }
249
250 Some(map)
251 } else if self.scenario {
252 Some(map_model::Map::load_synchronously(name.path(), timer))
253 } else {
254 None
255 };
256
257 if self.scenario {
258 if self.city == CityName::seattle() {
259 timer.start(format!("scenario for {}", name.describe()));
260 let scenario = soundcast::make_scenario(
261 "weekday",
262 maybe_map.as_ref().unwrap(),
263 maybe_popdat.as_ref().unwrap(),
264 maybe_huge_map.as_ref().unwrap(),
265 timer,
266 );
267 scenario.save();
268 timer.stop(format!("scenario for {}", name.describe()));
269
270 if name.map == "downtown"
272 || name.map == "qa"
273 || name.map == "south_seattle"
274 || name.map == "wallingford"
275 {
276 timer.start(format!("adjust parking for {}", name.describe()));
277 seattle::adjust_private_parking(maybe_map.as_mut().unwrap(), &scenario);
278 timer.stop(format!("adjust parking for {}", name.describe()));
279 }
280
281 timer.start("match parcels to buildings");
282 seattle::match_parcels_to_buildings(
283 maybe_map.as_mut().unwrap(),
284 maybe_zoning_parcels.as_ref().unwrap(),
285 timer,
286 );
287 timer.stop("match parcels to buildings");
288
289 if name.map == "central_seattle"
293 || name.map == "north_seattle"
294 || name.map == "south_seattle"
295 {
296 let map = maybe_map.as_mut().unwrap();
297 map.minify(timer);
298 map.save();
299 }
300 }
301
302 if self.city.country == "gb" {
303 if name == MapName::new("gb", "london", "central") {
304 let map = maybe_map.as_mut().unwrap();
306 map.minify_buildings(timer);
307 map.save();
308 } else {
309 uk::generate_scenario(maybe_map.as_ref().unwrap(), &config, timer)
310 .await
311 .unwrap();
312 }
313 }
314 }
315 timer.stop(name.describe());
316 }
317
318 if self.city_overview {
319 timer.start(format!(
320 "generate city overview for {}",
321 self.city.describe()
322 ));
323 abstio::write_binary(
324 abstio::path(format!(
325 "system/{}/{}/city.bin",
326 self.city.country, self.city.city
327 )),
328 &map_model::City::from_individual_maps(&self.city, timer),
329 );
330 timer.stop(format!(
331 "generate city overview for {}",
332 self.city.describe()
333 ));
334 }
335
336 timer.stop(format!("import {}", self.city.describe()));
337 }
338}