1use std::path::Path;
2use std::process::Command;
3
4use abstio::{CityName, MapName};
5use abstutil::{must_run_cmd, Timer};
6use map_model::RawToMapOptions;
7use raw_map::RawMap;
8
9use crate::configuration::ImporterConfiguration;
10
11pub async fn download(config: &ImporterConfiguration, output: String, url: &str) {
14 if Path::new(&output).exists() {
15 println!("- {} already exists", output);
16 return;
17 }
18 fs_err::create_dir_all(Path::new(&output).parent().unwrap())
20 .expect("Creating parent dir failed");
21
22 let tmp_file = format!("{output}_TMP");
23 let tmp = &tmp_file;
24 println!("- Missing {}, so downloading {}", output, url);
25 abstio::download_to_file(url, None, tmp).await.unwrap();
26
27 if url.contains(".zip") {
28 let unzip_to = if output.ends_with('/') {
29 output
30 } else {
31 Path::new(&output).parent().unwrap().display().to_string()
34 };
35 println!("- Unzipping into {}", unzip_to);
36 must_run_cmd(Command::new(&config.unzip).arg(tmp).arg("-d").arg(unzip_to));
37 fs_err::remove_file(tmp).unwrap();
38 } else if url.contains(".gz") {
39 println!("- Gunzipping");
40 fs_err::rename(tmp, format!("{}.gz", output)).unwrap();
41
42 let mut gunzip_cmd = Command::new(&config.gunzip);
43 for arg in config.gunzip_args.split_ascii_whitespace() {
44 gunzip_cmd.arg(arg);
45 }
46 must_run_cmd(gunzip_cmd.arg(format!("{}.gz", output)));
47 } else {
48 fs_err::rename(tmp, output).unwrap();
49 }
50}
51
52pub async fn download_kml(
55 output: String,
56 url: &str,
57 bounds: &geom::GPSBounds,
58 require_all_pts_in_bounds: bool,
59 timer: &mut Timer<'_>,
60) {
61 assert!(url.ends_with(".kml"));
62 if Path::new(&output).exists() {
63 println!("- {} already exists", output);
64 return;
65 }
66 fs_err::create_dir_all(Path::new(&output).parent().unwrap())
68 .expect("Creating parent dir failed");
69
70 let tmp_file = format!("{output}_TMP");
71 let tmp = &tmp_file;
72 if Path::new(&output.replace(".bin", ".kml")).exists() {
73 fs_err::copy(output.replace(".bin", ".kml"), tmp).unwrap();
74 } else {
75 println!("- Missing {}, so downloading {}", output, url);
76 abstio::download_to_file(url, None, tmp).await.unwrap();
77 }
78
79 println!("- Extracting KML data");
80
81 let shapes = kml::load(tmp.to_string(), bounds, require_all_pts_in_bounds, timer).unwrap();
82 abstio::write_binary(output.clone(), &shapes);
83 fs_err::rename(tmp, output.replace(".bin", ".kml")).unwrap();
86}
87
88pub fn osmium(
91 input: String,
92 clipping_polygon: String,
93 output: String,
94 config: &ImporterConfiguration,
95) {
96 if Path::new(&output).exists() {
97 println!("- {} already exists", output);
98 return;
99 }
100 fs_err::create_dir_all(Path::new(&output).parent().unwrap())
102 .expect("Creating parent dir failed");
103
104 println!("- Clipping {} to {}", input, clipping_polygon);
105
106 must_run_cmd(
108 Command::new(&config.osmium)
109 .arg("extract")
110 .arg("-p")
111 .arg(clipping_polygon)
112 .arg(input)
113 .arg("-o")
114 .arg(output)
115 .arg("-f")
116 .arg("pbf,add_metadata=false"),
118 );
119}
120
121pub async fn osm_to_raw(
123 name: MapName,
124 timer: &mut abstutil::Timer<'_>,
125 config: &ImporterConfiguration,
126) -> RawMap {
127 if name.city == CityName::seattle() {
128 crate::seattle::input(config, timer).await;
129 }
130 let opts = crate::map_config::config_for_map(&name);
131 if let Some(ref url) = opts.gtfs_url {
132 download(config, name.city.input_path("gtfs/"), url).await;
133 }
134
135 let boundary_polygon = format!(
136 "importer/config/{}/{}/{}.geojson",
137 name.city.country, name.city.city, name.map
138 );
139 let (osm_url, local_osm_file) = crate::pick_geofabrik(boundary_polygon.clone())
140 .await
141 .unwrap();
142 download(config, local_osm_file.clone(), &osm_url).await;
143
144 osmium(
145 local_osm_file,
146 boundary_polygon.clone(),
147 name.city.input_path(format!("osm/{}.osm.pbf", name.map)),
148 config,
149 );
150
151 let map = convert_osm::convert(
152 name.city.input_path(format!("osm/{}.osm.pbf", name.map)),
153 name.clone(),
154 Some(boundary_polygon),
155 opts,
156 timer,
157 );
158 map.save();
159 map
160}
161
162pub fn raw_to_map(name: &MapName, opts: RawToMapOptions, timer: &mut Timer) -> map_model::Map {
164 timer.start(format!("Raw->Map for {}", name.describe()));
165 let raw: RawMap = abstio::read_binary(abstio::path_raw_map(name), timer);
166 let map = map_model::Map::create_from_raw(raw, opts, timer);
167 timer.start("save map");
168 map.save();
169 timer.stop("save map");
170 timer.stop(format!("Raw->Map for {}", name.describe()));
171
172 if name.map == "huge_seattle" || name == &MapName::new("gb", "leeds", "huge") {
174 timer.start("generating city manifest");
175 abstio::write_binary(
176 abstio::path(format!(
177 "system/{}/{}/city.bin",
178 map.get_city_name().country,
179 map.get_city_name().city
180 )),
181 &map_model::City::from_huge_map(&map),
182 );
183 timer.stop("generating city manifest");
184 }
185
186 map
187}