1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use abstutil::{CmdArgs, Timer};
use geom::{GPSBounds, LonLat};
use std::fs::File;
use std::io::{Error, Write};
use std::process::Command;
fn main() {
let mut args = CmdArgs::new();
let input = args.required_free();
args.done();
let mut timer = Timer::new(format!("extract cities from {}", input));
let doc = convert_osm::reader::read(&input, &GPSBounds::new(), &mut timer).unwrap();
for (id, rel) in &doc.relations {
if !rel.tags.is("border_type", "city") {
continue;
}
let name = if let Some(name) = rel.tags.get("name") {
name
} else {
println!("{} has no name?", id);
continue;
};
println!("Found city relation for {}: {}", name, id);
let polygons = convert_osm::osm_geom::glue_multipolygon(
*id,
convert_osm::osm_geom::get_multipolygon_members(*id, rel, &doc),
None,
&mut timer,
);
println!(
"Extracted {} polygons for {} from {}, keeping the largest",
polygons.len(),
name,
id
);
let largest = polygons
.into_iter()
.max_by_key(|p| p.area() as usize)
.unwrap();
let clipping_polygon = format!("{}.poly", name);
write_osmosis_polygon(
&clipping_polygon,
doc.gps_bounds.convert_back(largest.points()),
)
.unwrap();
run(Command::new("osmconvert")
.arg(&input)
.arg(format!("-B={}", clipping_polygon))
.arg("--complete-ways")
.arg(format!("-o={}.osm", name)));
}
}
fn write_osmosis_polygon(path: &str, pts: Vec<LonLat>) -> Result<(), Error> {
let mut f = File::create(path)?;
writeln!(f, "boundary")?;
writeln!(f, "1")?;
for pt in pts {
writeln!(f, " {} {}", pt.x(), pt.y())?;
}
writeln!(f, "END")?;
writeln!(f, "END")?;
Ok(())
}
fn run(cmd: &mut Command) {
println!("- Running {:?}", cmd);
match cmd.status() {
Ok(status) => {
if !status.success() {
panic!("{:?} failed", cmd);
}
}
Err(err) => {
panic!("Failed to run {:?}: {:?}", cmd, err);
}
}
}