2020-07-04 21:29:45 +03:00
|
|
|
use geojson::feature::Id;
|
2020-10-29 22:23:39 +03:00
|
|
|
use geojson::{Feature, FeatureCollection, GeoJson};
|
2020-10-06 06:26:11 +03:00
|
|
|
|
2020-08-24 23:30:13 +03:00
|
|
|
use map_model::{Direction, Lane, LaneType, Map, RoadID};
|
2020-07-04 21:29:45 +03:00
|
|
|
|
2020-10-23 02:29:42 +03:00
|
|
|
/// Exports to https://github.com/d-wasserman/shared-row/, returns the filename
|
2020-09-30 22:40:36 +03:00
|
|
|
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("_")
|
|
|
|
);
|
2020-07-04 21:29:45 +03:00
|
|
|
let geojson = GeoJson::from(FeatureCollection {
|
|
|
|
bbox: None,
|
|
|
|
features: roads.into_iter().map(|r| road(r, map)).collect(),
|
|
|
|
foreign_members: None,
|
|
|
|
});
|
2020-09-30 22:40:36 +03:00
|
|
|
abstutil::write_json(path.clone(), &geojson);
|
|
|
|
path
|
2020-07-04 21:29:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn road(id: RoadID, map: &Map) -> Feature {
|
|
|
|
let r = map.get_r(id);
|
|
|
|
let mut properties = serde_json::Map::new();
|
|
|
|
// TODO Generate https://github.com/sharedstreets/sharedstreets-ref-system IDs
|
|
|
|
properties.insert("OID".to_string(), id.0.into());
|
|
|
|
properties.insert("sharedstreetid".to_string(), id.0.into());
|
|
|
|
|
|
|
|
let mut slices = Vec::new();
|
2020-08-25 01:39:17 +03:00
|
|
|
for (l, dir, _) in r.lanes_ltr() {
|
|
|
|
if let Some(mut slice) = lane(map.get_l(l)) {
|
2020-07-04 21:29:45 +03:00
|
|
|
slice
|
|
|
|
.entry("direction".to_string())
|
2020-08-25 01:39:17 +03:00
|
|
|
.or_insert(if dir == Direction::Fwd {
|
|
|
|
"forward".into()
|
|
|
|
} else {
|
|
|
|
"reverse".into()
|
|
|
|
});
|
2020-07-04 21:29:45 +03:00
|
|
|
slices.push(serde_json::value::Value::Object(slice));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
properties.insert(
|
|
|
|
"slices".to_string(),
|
|
|
|
serde_json::value::Value::Array(slices),
|
|
|
|
);
|
|
|
|
|
|
|
|
Feature {
|
|
|
|
bbox: None,
|
2020-10-29 22:23:39 +03:00
|
|
|
geometry: Some(r.center_pts.to_geojson(Some(map.get_gps_bounds()))),
|
2020-07-04 21:29:45 +03:00
|
|
|
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();
|
|
|
|
// TODO We don't really model turn lanes yet; they'll all show up as drive_lane
|
|
|
|
slice.insert(
|
|
|
|
"type".to_string(),
|
|
|
|
match lane.lane_type {
|
|
|
|
LaneType::Driving => "drive_lane".into(),
|
|
|
|
LaneType::Parking => "parking".into(),
|
|
|
|
LaneType::Sidewalk => "sidewalk".into(),
|
2020-07-30 23:42:36 +03:00
|
|
|
// TODO Nope
|
|
|
|
LaneType::Shoulder => "sidewalk".into(),
|
2020-07-04 21:29:45 +03:00
|
|
|
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());
|
|
|
|
// TODO Spec says required but shouldn't be
|
|
|
|
slice.insert("material".to_string(), "asphalt".into());
|
|
|
|
Some(slice)
|
|
|
|
}
|