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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use anyhow::Result;
use abstutil::Timer;
use geom::{PolyLine, Pt2D};
use widgetry::EventCtx;
use super::Neighborhood;
use crate::app::App;
pub fn write_geojson_file(ctx: &EventCtx, app: &App, timer: &mut Timer) -> Result<String> {
if cfg!(target_arch = "wasm32") {
bail!("Export only supported in the installed version");
}
use geo::algorithm::map_coords::MapCoordsInplace;
use geojson::{Feature, FeatureCollection, GeoJson, Geometry, Value};
use std::io::Write;
let map = &app.primary.map;
let mut features = Vec::new();
for (id, (block, color)) in &app.session.partitioning.neighborhoods {
let mut feature = Feature {
bbox: None,
geometry: Some(block.polygon.to_geojson(None)),
id: None,
properties: None,
foreign_members: None,
};
feature.set_property("type", "neighborhood");
feature.set_property("fill", color.as_hex());
feature.set_property("fill-opacity", 0.0);
features.push(feature);
let render_cells =
super::draw_cells::RenderCells::new(map, &Neighborhood::new(ctx, app, *id));
for (idx, multipolygon) in render_cells.to_multipolygons(timer).into_iter().enumerate() {
let mut feature = Feature {
bbox: None,
geometry: Some(Geometry {
bbox: None,
value: Value::from(&multipolygon),
foreign_members: None,
}),
id: None,
properties: None,
foreign_members: None,
};
feature.set_property("type", "cell");
feature.set_property("fill", render_cells.colors[idx].as_hex());
features.push(feature);
}
}
for (r, dist) in &app.session.modal_filters.roads {
let road = map.get_r(*r);
if let Ok((pt, angle)) = road.center_pts.dist_along(*dist) {
let road_width = road.get_width();
let pl = PolyLine::must_new(vec![
pt.project_away(0.8 * road_width, angle.rotate_degs(90.0)),
pt.project_away(0.8 * road_width, angle.rotate_degs(-90.0)),
]);
let mut feature = Feature {
bbox: None,
geometry: Some(pl.to_geojson(None)),
id: None,
properties: None,
foreign_members: None,
};
feature.set_property("type", "road filter");
feature.set_property("stroke", "red");
features.push(feature);
}
}
for (_, filter) in &app.session.modal_filters.intersections {
let pl = filter.geometry(map).to_polyline();
let mut feature = Feature {
bbox: None,
geometry: Some(pl.to_geojson(None)),
id: None,
properties: None,
foreign_members: None,
};
feature.set_property("type", "diagonal filter");
feature.set_property("stroke", "red");
features.push(feature);
}
let gps_bounds = map.get_gps_bounds();
for feature in &mut features {
let mut geom: geo::Geometry<f64> = feature.geometry.take().unwrap().value.try_into()?;
geom.map_coords_inplace(|c| {
let gps = Pt2D::new(c.0, c.1).to_gps(gps_bounds);
(gps.x(), gps.y())
});
feature.geometry = Some(Geometry {
bbox: None,
value: Value::from(&geom),
foreign_members: None,
});
}
let gj = GeoJson::FeatureCollection(FeatureCollection {
features,
bbox: None,
foreign_members: None,
});
let path = format!("ltn_{}.geojson", map.get_name().map);
let mut file = std::fs::File::create(&path)?;
write!(file, "{}", serde_json::to_string_pretty(&gj)?)?;
Ok(path)
}