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
use geojson::feature::Id;
use geojson::{Feature, FeatureCollection, GeoJson};
use map_model::{Direction, Lane, LaneType, Map, RoadID};
pub fn export(roads: Vec<RoadID>, map: &Map) -> String {
let path = format!(
"shared_row_export_{}.json",
roads
.iter()
.take(5)
.map(|r| r.0.to_string())
.collect::<Vec<_>>()
.join("_")
);
let geojson = GeoJson::from(FeatureCollection {
bbox: None,
features: roads.into_iter().map(|r| road(r, map)).collect(),
foreign_members: None,
});
abstutil::write_json(path.clone(), &geojson);
path
}
fn road(id: RoadID, map: &Map) -> Feature {
let r = map.get_r(id);
let mut properties = serde_json::Map::new();
properties.insert("OID".to_string(), id.0.into());
properties.insert("sharedstreetid".to_string(), id.0.into());
let mut slices = Vec::new();
for (l, dir, _) in r.lanes_ltr() {
if let Some(mut slice) = lane(map.get_l(l)) {
slice
.entry("direction".to_string())
.or_insert(if dir == Direction::Fwd {
"forward".into()
} else {
"reverse".into()
});
slices.push(serde_json::value::Value::Object(slice));
}
}
properties.insert(
"slices".to_string(),
serde_json::value::Value::Array(slices),
);
Feature {
bbox: None,
geometry: Some(r.center_pts.to_geojson(Some(map.get_gps_bounds()))),
id: Some(Id::Number(id.0.into())),
properties: Some(properties),
foreign_members: None,
}
}
fn lane(lane: &Lane) -> Option<serde_json::Map<String, serde_json::value::Value>> {
let mut slice = serde_json::Map::new();
slice.insert(
"type".to_string(),
match lane.lane_type {
LaneType::Driving => "drive_lane".into(),
LaneType::Parking => "parking".into(),
LaneType::Sidewalk => "sidewalk".into(),
LaneType::Shoulder => "sidewalk".into(),
LaneType::Biking => "bike_lane".into(),
LaneType::Bus => "bus_lane".into(),
LaneType::SharedLeftTurn => "turn_lane".into(),
LaneType::Construction => "construction_zone".into(),
LaneType::LightRail => {
return None;
}
},
);
if lane.lane_type == LaneType::SharedLeftTurn {
slice.insert("direction".to_string(), "bidirectional".into());
}
slice.insert("width".to_string(), lane.width.inner_meters().into());
slice.insert("height".to_string(), 0.0.into());
slice.insert("material".to_string(), "asphalt".into());
Some(slice)
}