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
use anyhow::Result;
use geom::{PolyLine, Pt2D};
use widgetry::EventCtx;
use crate::{App, Neighbourhood};
pub fn write_geojson_file(ctx: &EventCtx, app: &App) -> Result<String> {
let contents = geojson_string(ctx, app)?;
let path = format!("ltn_{}.geojson", app.map.get_name().map);
abstio::write_file(path, contents)
}
fn geojson_string(ctx: &EventCtx, app: &App) -> Result<String> {
use geo::MapCoordsInPlace;
use geojson::{Feature, FeatureCollection, GeoJson, Geometry, Value};
let map = &app.map;
let mut features = Vec::new();
for (id, info) in app.session.partitioning.all_neighbourhoods() {
let mut feature = Feature {
bbox: None,
geometry: Some(info.block.polygon.to_geojson(None)),
id: None,
properties: None,
foreign_members: None,
};
feature.set_property("type", "neighbourhood");
features.push(feature);
let render_cells =
crate::draw_cells::RenderCells::new(map, &Neighbourhood::new(ctx, app, *id));
for (idx, multipolygon) in render_cells.to_multipolygons().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, filter_type)) 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("filter_type", format!("{:?}", filter_type));
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("filter_type", format!("{:?}", filter.filter_type));
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 = feature.geometry.take().unwrap().value.try_into()?;
geom.map_coords_in_place(|c| {
let gps = Pt2D::new(c.x, c.y).to_gps(gps_bounds);
(gps.x(), gps.y()).into()
});
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 x = serde_json::to_string_pretty(&gj)?;
Ok(x)
}