1use anyhow::Result;
2use geo::MapCoordsInPlace;
3use geojson::{Feature, FeatureCollection, GeoJson, Value};
4
5use geom::{PolyLine, Pt2D};
6use osm2streets::Direction;
7
8use crate::{render, App, Neighbourhood};
9
10pub fn geojson_string(app: &App) -> Result<String> {
11 let map = &app.per_map.map;
12 let gps_bounds = Some(map.get_gps_bounds());
13 let mut features = Vec::new();
14
15 for (id, info) in app.partitioning().all_neighbourhoods() {
17 let mut feature = Feature::from(info.block.polygon.to_geojson(gps_bounds));
18 feature.set_property("type", "neighbourhood");
19 features.push(feature);
20
21 let render_cells = render::RenderCells::new(map, &Neighbourhood::new(app, *id));
23 for (idx, mut multipolygon) in render_cells.to_multipolygons().into_iter().enumerate() {
24 multipolygon.map_coords_in_place(|c| {
26 let gps = Pt2D::new(c.x, c.y).to_gps(map.get_gps_bounds());
27 (gps.x(), gps.y()).into()
28 });
29 let mut feature = Feature::from(Value::from(&multipolygon));
30 feature.set_property("type", "cell");
31 feature.set_property("fill", render_cells.colors[idx].as_hex());
32 features.push(feature);
33 }
34 }
35
36 for (road, filter) in map.all_roads_with_modal_filter() {
38 if let Ok((pt, angle)) = road.center_pts.dist_along(filter.dist) {
39 let road_width = road.get_width();
40 let pl = PolyLine::must_new(vec![
41 pt.project_away(0.8 * road_width, angle.rotate_degs(90.0)),
42 pt.project_away(0.8 * road_width, angle.rotate_degs(-90.0)),
43 ]);
44 let mut feature = Feature::from(pl.to_geojson(gps_bounds));
45 feature.set_property("type", "road filter");
46 feature.set_property("filter_type", format!("{:?}", filter.filter_type));
47 feature.set_property("stroke", "red");
48 features.push(feature);
49 }
50 }
51 for i in map.all_intersections() {
52 if let Some(ref filter) = i.modal_filter {
53 let pl = filter.geometry(map).to_polyline();
54 let mut feature = Feature::from(pl.to_geojson(gps_bounds));
55 feature.set_property("type", "diagonal filter");
56 feature.set_property("filter_type", format!("{:?}", filter.filter_type));
57 feature.set_property("stroke", "red");
58 features.push(feature);
59 }
60 }
61
62 for road in map.all_roads() {
65 if crate::is_driveable(road, map) {
66 let mut feature = Feature::from(road.center_pts.to_geojson(gps_bounds));
67 feature.set_property("type", "direction");
68 feature.set_property(
69 "direction",
70 match road.oneway_for_driving() {
71 Some(Direction::Fwd) => "one-way forwards",
72 Some(Direction::Back) => "one-way backwards",
73 None => "two-ways",
74 },
75 );
76 feature.set_property("stroke", "blue");
77 features.push(feature);
78 }
79 }
80
81 for road in map.all_roads() {
82 for crossing in &road.crossings {
83 let mut feature = Feature::from(
84 road.center_pts
85 .must_dist_along(crossing.dist)
86 .0
87 .to_geojson(gps_bounds),
88 );
89 feature.set_property("type", "crossing");
90 feature.set_property("crossing_type", format!("{:?}", crossing.kind));
91 features.push(feature);
92 }
93 }
94
95 let gj = GeoJson::FeatureCollection(FeatureCollection {
96 features,
97 bbox: None,
98 foreign_members: None,
99 });
100
101 let x = serde_json::to_string_pretty(&gj)?;
102 Ok(x)
103}